home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-06-06 | 235.0 KB | 4,805 lines |
-
-
-
-
-
- Intellicomm (TM)
- v2.01
- Copyright (C) 1991-1994 Liberation Enterprises. All rights reserved.
- ---------------------------------------------------------------------
- INTELLICOMM SCRIPT LANGUAGE TUTORIAL
- ---------------------------------------------------------------------
-
-
- TABLE OF CONTENTS
-
-
- 1. INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . 1
- 1.1 What are Scripts? . . . . . . . . . . . . . . . . . . . . . 1
- 1.2 Why Should I Bother With Scripts? . . . . . . . . . . . . . 1
- 1.3 Is This Going to Take HOURS? . . . . . . . . . . . . . . . . 2
- 1.4 Script Learn Mode . . . . . . . . . . . . . . . . . . . . . 2
- 1.5 How Do I Create a Script? . . . . . . . . . . . . . . . . . 3
- 1.6 Icom's Internal Editor vs. an External Editor . . . . . . . 4
- 1.7 Stopping Scripts . . . . . . . . . . . . . . . . . . . . . . 4
- 1.8 Creating and Running Your First Script . . . . . . . . . . . 5
- 1.9 A More Exciting Example . . . . . . . . . . . . . . . . . . 6
- 1.10 Other Ways of Running Scripts . . . . . . . . . . . . . . . 8
- 1.10.1 Running Script from BIFs (8); 1.10.2 Running
- Scripts from Jobs (8); 1.10.3 Running Scripts from DOS
- (9); 1.10.4 Running Scripts from Scripts (9); 1.10.5
- Running Scripts from the Script Manager (9); 1.10.6
- Running Scripts via Function Keys (10)
- 1.11 It Can't be That Simple, Can It? . . . . . . . . . . . . 10
- 1.12 Variable Overview . . . . . . . . . . . . . . . . . . . . 15
- 1.13 A Word on Formatting . . . . . . . . . . . . . . . . . . 18
- 1.14 Why the Double Quotes ""? . . . . . . . . . . . . . . . . 19
- 1.15 Specifying Control Characters . . . . . . . . . . . . . . 19
- 1.16 Tildes . . . . . . . . . . . . . . . . . . . . . . . . . 20
- 1.17 Specifying Numbers . . . . . . . . . . . . . . . . . . . 20
- 1.18 Numeric Limits . . . . . . . . . . . . . . . . . . . . . 21
- 1.19 Compound Statements . . . . . . . . . . . . . . . . . . . 21
- 1.20 Where To Go From Here . . . . . . . . . . . . . . . . . . 23
- 1.21 The Secret to Success . . . . . . . . . . . . . . . . . . 24
-
- 2. WHAT HAPPENS WHEN A SCRIPT ENDS? . . . . . . . . . . . . . . . 26
- 2.1 EXIT and RETURN Error codes . . . . . . . . . . . . . . . 27
- 2.2 Using the HANGUP Command for Error-Recovery . . . . . . . 28
-
- 3. INTRODUCTION TO SUBROUTINES (GOSUB) . . . . . . . . . . . . . . 28
- 3.1 When to use a Subroutine . . . . . . . . . . . . . . . . . 28
- 3.2 Writing a Subroutine . . . . . . . . . . . . . . . . . . . 29
- 3.3 GOSUB In Detail . . . . . . . . . . . . . . . . . . . . . 30
- 3.4 Creating a Subroutine Template . . . . . . . . . . . . . . 31
-
- 4. SCRIPT VARIABLES IN DETAIL . . . . . . . . . . . . . . . . . . 32
- 4.1 Why Would I Want to Use Variables? . . . . . . . . . . . . 32
- 4.2 Where you CAN'T use Variables . . . . . . . . . . . . . . 32
- 4.3 User-Defined Variables . . . . . . . . . . . . . . . . . . 32
- 4.4 User-Defined Variable Rules . . . . . . . . . . . . . . . 33
- 4.5 Why All the Rules? . . . . . . . . . . . . . . . . . . . . 35
- 4.6 Using Variables . . . . . . . . . . . . . . . . . . . . . 36
- 4.7 The Life of a Variable . . . . . . . . . . . . . . . . . . 37
- 4.8 Global Variables . . . . . . . . . . . . . . . . . . . . . 38
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC ii
-
-
-
- 4.9 Using Global Variables . . . . . . . . . . . . . . . . . . 40
- 4.10 Passing Parameters to Scripts . . . . . . . . . . . . . . 41
- 4.11 Checking the Number of Passed Parameters . . . . . . . . 43
- 4.12 System Variables . . . . . . . . . . . . . . . . . . . . 44
- 4.13 BIF Variables . . . . . . . . . . . . . . . . . . . . . . 45
- 4.14 Main Setup and Environment Variables . . . . . . . . . . 45
- 4.15 Environment Variables . . . . . . . . . . . . . . . . . . 45
-
- 5. PERMANENT VARIABLES: INTRODUCTION TO FILE INPUT/OUTPUT . . . . 46
- 5.1 FOPEN 'Modes' . . . . . . . . . . . . . . . . . . . . . . 47
- 5.2 The File Handle . . . . . . . . . . . . . . . . . . . . . 48
- 5.3 Testing for End-of-File . . . . . . . . . . . . . . . . 53
- 5.4 How to store settings on-disk . . . . . . . . . . . . . . 53
- 5.5 Moving the File Pointer (Advanced Use Only) . . . . . . . 54
- 5.6 Opening a File for Reading AND Writing (Advanced use only) 57
- 5.7 Upating an Old Data File . . . . . . . . . . . . . . . . . 59
-
- 6. INTRODUCTION TO DATABASE COMMANDS (FILE TAGGER CATALOGS) . . . 62
- 6.1 Why would I want to use the catalog-oriented commands? . . 62
- 6.2 What is a Database? . . . . . . . . . . . . . . . . . . . 62
- 6.3 Indexes . . . . . . . . . . . . . . . . . . . . . . . . . 63
- 6.4 Using File Tagger Indexes . . . . . . . . . . . . . . . . 64
- 6.5 How this all applies to Scripts . . . . . . . . . . . . . 65
- 6.6 The View Date . . . . . . . . . . . . . . . . . . . . . . 70
- 6.7 Getting Around in a Catalog . . . . . . . . . . . . . . . 71
- 6.8 Getting the Total Number of Records . . . . . . . . . . . 72
- 6.9 The View Date and Tagged/Noted Files . . . . . . . . . . . 73
-
- 7. USING THE SCRIPT DEBUGGER . . . . . . . . . . . . . . . . . . . 74
- 7.1 What are BUGS, and What is a DEBUGGER? . . . . . . . . . . 74
- 7.2 Using the Debugger . . . . . . . . . . . . . . . . . . . . 75
- 7.3 Checking the Contents of a Single Variable . . . . . . . . 77
- 7.4 Debug Hotkeys . . . . . . . . . . . . . . . . . . . . . . 78
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 1
-
-
-
- 1. INTRODUCTION
-
-
- 1.1 What are Scripts?
-
- Scripts are files which contain one or more instructions (commands) for
- Intellicomm to carry out. You can't 'talk' to Intellicomm to tell it
- what to do when you have custom work to do (at least, not to my
- knowledge... <grin>), so the next best thing is to write it down and let
- Intellicomm read it. As a movie script tells the cast what to say and
- do: Intellicomm scripts tell Intellicomm what to say and do. You're the
- script writer and Intellicomm is your cast.
-
- Don't confuse scripts with Icom's automated jobs and BIFs. The jobs you
- run from the Job Directory and set up in the Job Editor are not scripts;
- they're called Jobs and they are carried out by ICOM.EXE's built-in
- automated routines, using BBS Information File (BIF) data. Jobs are
- jobs, BIFs are BIFs, and scripts are scripts. They're three different
- things, and this document discusses scripts only. For information on
- Icom's internal jobs (automated file uploads and downloads, mail
- transfers and time bank transactions, etc.) please refer to the online
- help, and particularly to "BIF Learn".
-
- 1.2 Why Should I Bother With Scripts?
-
- There are limitless benefits awaiting those who learn some (or all) of
- Intellicomm's script language, and learn the simple process of creating
- scripts. Most importantly, you will gain an incredibly flexible and
- powerful tool to add to your automation arsenal. Virtually ANYTHING you
- can dream up can be automated with a script, while BIFs and automated
- jobs (aside from the job "Custom Commands" which allow limited custom
- work) were designed for specific tasks.
-
- With scripts you can automate *any* BBS task by watching for specific
- text from the BBS and handling it as you see fit (send responses to the
- BBS, transfer files, display information on the screen, and do any number
- of other things). If desired, you can easily define your own custom
- interfaces using menus and other interactive functions for interactive
- user input, you can display multiple boxes/windows and other text on the
- screen (including the ability to display incoming text from the *BBS* in
- a window) using a bevy of powerful video-oriented script commands, you
- can run other DOS programs (or .BAT files, or other Icom scripts), pause
- script execution until a specific time and/or day, create, display, and
- otherwise maintain File Tagger catalogs in every way imagineable, read
- from and write to text files on-disk (save information permanently),
- display text files in the File Viewer or load them into the Editor for
- the user to view/modify, test for certain system conditions (date, time,
- day-of-week, etc.), get and set BIF and Icom main setup information,
- create 'keyboard macros', and on and on.
-
- Those who gain control over both Icom's built-in jobs AND its script
- language (and script learn mode, for registered users) truly have the
- most powerful and flexible set of tools available for automated BBS
- communications, probably anywhere in the universe. If automation, and
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 2
-
-
-
- taking the drudgery out of your online sessions is your passion, you
- can't beat that prospect!
-
- 1.3 Is This Going to Take HOURS?
-
- Don't be discouraged by the size of the script manuals. The script
- language and manuals are like a big bowl of peanuts: take what you want.
- You don't have to eat the whole bowl to enjoy yourself and get something
- useful done, and you'll be able to write very useful scripts after
- reading just the next few pages below. If you just want the basics, and
- the basics are VERY powerful and useful indeed, you should be finished in
- half-an-hour or less. If you end up drooling at the possibilities and
- want the whole bowl of peanuts, it'll take some practice (and some more
- reading) to get the whole language down. But it's your choice, and
- making progress and getting things DONE is a quick process as you'll soon
- see.
-
- You don't even have to print this document if you don't have the time or
- paper: Just read it in the help system ("SCRTUTOR.DOC" link; make sure
- SCRTUTOR.DOC is in the same directory as ICOM.EXE) or text viewer (via
- the Icom File Manager / "View" option) until you're satisfied with what
- you've learned. The script documents should be used as follows:
-
- 1. Read the introductory material in this document until you're happy
- with what you've learned. This document gives you the basics and,
- more importantly, shows you how to put script commands together to
- get something practical done.
-
- 2. Once you've got the basics down, use the "SCRIPT COMMANDS AT A
- GLANCE" section at the beginning of SCRIPT.DOC to find the command(s)
- you're interested in, and to refresh your memory as to what various
- commands do.
-
- 3. When you find the command you want, using step 2 above, look it up in
- the DETAILED COMMAND SUMMARY (sorted alphabetically by script
- command) in SCRIPT.DOC to quickly get all the details along with an
- EXAMPLE showing how to use the command.
-
- TIP: If you view SCRIPT.DOC from Icom's internal File Viewer or help
- system, to locate a command summary press [Alt-F] (Find) then type the
- command you're interested in, follow that with an underscore (e.g.
- PRINT_) then carry out the search DOWNWARDS to find the Detailed Summary
- in a flash. All commands in the Detailed Command Summary of SCRIPT.DOC
- are followed by a line of underscores to allow you to find commands
- quickly. The Table of Contents, and the index at the back of the
- manuals can also be used to locate information quickly. Many people
- skip the Table of Contents, but you can learn a lot by looking at it
- carefully. You'll see how the manuals are laid out, and more
- importantly can quickly see every major topic that is covered -- which
- can be useful to know when you have a question later.
-
- 1.4 Script Learn Mode
-
- The easiest way to become acquainted with scripts is to use Icom's script
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 3
-
-
-
- learn mode (a bonus feature in the registered version). With script
- learn mode you simply turn it on, then just 'do' whatever it is you want
- automated. Icom watches what you do and writes a script for you! Not
- only do you save time getting your scripts written, but it's also quite
- educational: by looking at the script Icom creates, you can learn how the
- script language works.
-
- Script Learn is accessed through the "Learn Modes" option of the Main
- Menu or Job Directory or Terminal "Tools" menu, and in various other
- places. Pressing [Alt-Q] from just about anywhere in Intellicomm calls
- up the Learn Modes menu.
-
- Use of Script Learn is quite straightforward, and is covered in the
- online help if you have questions.
-
- 1.5 How Do I Create a Script?
-
- Writing a script (or modifying/adding to one started with Script Learn)
- is much the same as typing a letter in your word processor. Instead of
- using a word processor though, which places printer commands and
- formatting codes all over the document, you instead use a "Text Editor"
- to create scripts.
-
- Text Editors work similarly to word processors as far as typing,
- deleting, cutting/pasting text, etc. But they don't add printer codes to
- the files you save to disk -- and they usually don't force margins on
- you, which is essential for writing scripts. Script command lines will
- sometimes be longer than your screen width, and thus the margins in word
- processors which 'wrap' long lines are not acceptable. The files Text
- Editors produce are called "text files", or "ASCII files" and these are
- the types of files Icom requires for scripts -- without any printer
- formatting codes or margins.
-
- Intellicomm comes with a built-in Text Editor, though you can use your
- favorite external Text Editor if you like (details in a second). For
- script writing, the editor (whether internal or external) is best
- accessed through the Icom "Script Manager". By accessing the Script
- Manager first you can be sure that your scripts will be saved in the
- proper directory; since Icom changes DOS to the Script Directory
- (\ICOM\SCR by default) when you enter the Script Manager. From the
- editor you just save your scripts in the current directory (without
- specifying a drive letter or \DIRECTORY\ name), and they always end up in
- the right place, where Icom expects them to be.
-
- The Script Manager can be accessed from the Icom Main Menu (and at
- various other menus), or by simply pressing [Alt-U] from just about
- anywhere in Intellicomm. [Sorry about the 'U'; it doesn't help much in
- remembering the key, but unfortunately [Alt-S] (S for Script) is a fairly
- standard 'Screen Capture' command and is used by the Terminal.]
-
- Once in the Script Manager, select "Create" from the bottom menu to
- create a new script, or hilight the script of interest and select "Edit"
- to view/modify an existing script, or hilight a script and select "Run"
- to execute it (the other options in the Script Manager are fairly self-
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 4
-
-
-
- explanatory... please see the online help if you need more information).
-
- There are several scripts included with Intellicomm for demonstration and
- other purposes. You can enter the Script Manager, hilight and "Run"
- SCRDEMO.SCR from the Script Manager now if you want to see a script in
- action before you continue reading. SCRDEMO.SCR can also be viewed after
- you run it, for many useful examples. Note that Intellicomm itself
- doesn't use SCRDEMO.SCR for anything, so you can delete the file when
- you're done with it, if you're short on disk space.
-
- 1.6 Icom's Internal Editor vs. an External Editor
-
- If you use Icom's internal Text Editor, you gain the advantage of online
- script writing help (online access to the documentation). So, when you
- forget one of the script commands we'll be discussing below you can
- simply press the [F1] help key, and call up the index of script help.
- You can view this document (if installed in the \ICOM directory) or
- SCRIPT.DOC to obtain any information you require, without leaving the
- editor by accessing the SCRTUTOR.DOC or SCRIPT.DOC help links (available
- from the "Script Language" Index, and various other places).
-
- A further advantage of using the internal editor is that if by chance you
- make a typing mistake in your script, then Run the script before noticing
- the error; Icom will be able to load the script into the internal editor,
- position the cursor right on the line of the script where the error
- occurred, displaying the error message to you so you can fix it. With an
- external editor Icom will still call your editor if an error is found,
- and if your editor accepts a filename on the command line the script will
- be loaded for you, but you won't be moved to the proper line number. You
- can get the error message (which includes the number of the line on which
- the error occurred) from the file \ICOM\SCRIPT.ERR while in your external
- editor, but unless you're proficient with your external editor and are
- used to doing this sort of thing (with other script languages or program
- compilers), you're probably better off using Icom's internal editor for
- the time being.
-
- To use an external editor you must define the editor command in the Icom
- main setup (accessed via the main menu "Intellicomm Setup" option), on
- the "Filenames and Paths" screen. Hilight the "Extnl Editor" item, then
- press [Enter] and enter the command you'd normally use to start your
- editor from the *DOS command prompt* there, and save your setup. Icom
- will then call your external editor when you select "Create" or "Edit"
- from within the Script Manager or when a script error occurs.
-
- If you defined an external editor previously and wish to reverse your
- decision for now and use the internal editor, do the same as outlined
- above but CLEAR the "Extnl Editor" item in the main setup (hold down the
- [Del] key until the item is clear, or press [Ctrl-End] once to clear the
- item while editing it), then re-save your setup. Icom will then use its
- internal text editor.
-
- 1.7 Stopping Scripts
-
- Before we create and run a script, it'll be useful for you to first know
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 5
-
-
-
- how to STOP one, if something goes wrong. To stop a script, just press
- [Alt-Q] (Q for Quit), relax (the script is paused while you're in the
- [Alt-Q] menu or any other menu) then select "Abort Script Only" to cancel
- the script without cancelling the entire job (if the script was called
- during an automated job... more on that later), or select "Abort
- Job/Script" to cancel both the script and the job. To activate script
- debugging, which runs a script one line at a time, showing you each line
- before it is executed select "Script DEBUG" from the [Alt-Q] menu.
- Script debug can also be helpful in learning script writing, since it
- slows script execution down, allowing you to study each command before it
- is executed, and see its result after it is executed.
-
- If you forget the [Alt-Q] command, just press [Alt-Z] to pop up the
- Terminal menu (the terminal is where all scripts are executed from,
- regardless of where they're started from) and select "Job and Script
- Control Menu" from the menu, which has the same effect as pressing [Alt-
- Q] from the Terminal. [Alt-Z] can be your panic button if you forget the
- [Alt-Q] key.
-
- 1.8 Creating and Running Your First Script
-
- Most computer language tutorials begin by showing the student how to
- print the message "Hello, World" to the screen. It's a quick way to
- actually accomplish something, so we'll start by doing this here as well.
-
- To begin, start Icom if necessary, then access the Script Manager by
- pressing [Alt-U]. If [Alt-U] doesn't work, then you're in an area of
- Icom where the hotkeys are disabled, and you'll have to exit that area
- back to any 'major' Icom area, then try again. Note that these "follow
- along while reading" bits are very quick, so if you're considering
- printing this document now, don't (unless you don't mind doing so). For
- 99% of the tutorial you will simply read along in the online help or File
- Viewer, (without wasting paper) without 'doing' anything but learning.
- Just grab a piece of paper and write the few short script lines down
- before exiting this document and entering the Script Manager. Writing
- the commands down also helps the brain to remember things better.
-
- From the Script Manager select "Create" to enter the editor (whether
- internal or external) to create a new script.
-
- Once in the editor type the two lines below, pressing the [Enter] key
- after each line. If you make a mistake, use the backspace key (just
- above the [Enter] key) to correct it. Case is not significant when
- entering script commands; 'PRINT', 'Print', and 'print' all do the same
- thing. Use whichever you prefer:
-
- print "Hello, World!"
- pause
-
- Once you have these two lines entered, save the file as HELLO.SCR and
- exit the editor (from Icom's internal editor, just press the [Esc] key to
- exit, answer "Yes" when asked if you want to save your work, then enter
- HELLO.SCR when asked for a filename. You're on your own if you're using
- an external editor. See your editor's help screens if you don't know how
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 6
-
-
-
- to save and exit.) If you're asked whether to overwrite an existing
- file, someone probably gave you a copy of Intellicomm that had already
- been "used" (they already read this and created their own HELLO.SCR). If
- that's the case just overwrite the existing file when asked.
-
- Once you return to the Script Manager you should see HELLO.SCR displayed
- in the list of script filenames. To execute the script, move the top
- hilight bar to HELLO.SCR with the [Up] / [Down] cursor keys (or move the
- mouse cursor to HELLO.SCR and click), then select "Run" from the bottom
- menu by pressing the [R] key, or by moving the mouse cursor to "Run" and
- clicking.
-
- Intellicomm should then switch to the Terminal screen, print the message
- Hello, World! to the screen, and pause for a keystroke. When you press a
- key the script will end and you will be returned to the Script Manager.
-
- Did it work? If so, congratulations! If not, please start over, and
- check your typing carefully. You may have missed a " quote or left a
- space out accidentally.
-
- 1.9 A More Exciting Example
-
- It's nice to be able to print the message "Hello, World" to the screen,
- but it certainly isn't very impressive or exciting. Let's try something
- a little more interesting this time.
-
- You know what 'menus' are if you've been using Icom for any length of
- time, and now it's time to demonstrate how easy it is to create a menu
- using an Icom script. You may even impress your friends or co-workers
- with this next script!
-
- Select "Create" again from the Script Manager to enter the editor and
- create a new script, then type in these three lines exactly, double-
- checking all the quotes, spaces and tildes (~):
-
- MENUDEFINE "Option ~1" "Option ~2" "-" "Option ~3" "Option ~4"
- MENUBOXV "My Own Menu" "Your selection, Sir?"
- PAUSE "You selected Option " $MENUSELECTION
-
- When done, save the script to disk but this time as MENU.SCR (from the
- internal editor, press [Esc], answer "Yes" to save it, then enter
- MENU.SCR when asked for a filename; again overwrite if a MENU.SCR already
- exists). When you return to the Script Manager, hilight MENU.SCR and
- select "Run" to see what you've created.
-
- If you entered the lines above exactly, you'll have created a centered
- box menu, with title, four menu options with a divider line separating
- items 2 and 3, hotkeys, and mouse support! Of course, the menu doesn't
- actually 'do' anything yet other than print which option you selected (or
- 0 if you press the [Esc] key)... you'd have to add a few more lines to
- the script to get the options to do something.
-
- However, just being able to display such a menu on the screen with
- working hilight bars and mouse support (and even a screen blanker, if
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 7
-
-
-
- that feature is turned on in the Icom main setup) is no small programming
- task. Yet you accomplished it in about 30 seconds! We used "Option ~1"
- and so forth above, but the options can be any text you like; as long all
- the options remain on the same line, each in double quotes, separated
- from one another by a space. The "~" character tells MENUDEFINE where
- the 'hotkey' is. Using a single hypen "-" as a menu option specifies a
- divider line.
-
- $MENUSELECTION is a 'System Variable' which Icom sets after menu-handling
- commands to tell you which (if any) item was selected from the menu.
- There are about a hundred of these System Variables available (all
- starting with $) and each is documented fully in SCRIPT.DOC.
-
- By testing the $MENUSELECTION variable with an IF or SWITCH command, you
- could have various other commands carried out according to the menu
- option the user selected. Example (text after a semicolon ; is ignored
- by the script processor and is used to make comments for human
- consumption):
-
- ;The first IF means "IF $MENUSELECTION is equal to 1" If it is, then
- ; the command following the IF is executed. If not, the command is
- ; skipped.
-
- IF $MENUSELECTION = 1
- print "Downloading file..." ;these commands are only
- download "Z" "" ; executed IF $MENUSELECTION
- ...etc. ; is equal to 1
- ENDIF
- IF $MENUSELECTION = 2 gosub Item1Selected ;go to a subroutine
-
- A better way to test the value of $MENUSELECTION though is to use the
- SWITCH command. SWITCH is designed specifically to test a variable such
- as $MENUSELECTION for multiple conditions, and to carry out one command
- (or set of commands) according to the value of the variable. Read the
- comments (after ;) for an explanation:
-
- SWITCH $MENUSELECTION ;specify the variable to test
- case 1 ;is $MENUSELECTION equal to 1?
- print "Option 1 selected" ; yes, print this
- ... ; execute as many commands as you like
- endcase ;'end of case 1' (the rest are skipped)
- case 2 ;is $MENUSELECTION equal to 2?
- print "Option 2 selected" ; yes, print this
- ... ; and execute whatever commands you like
- endcase ;'end of case 2' (the rest are skipped)
- ... ;and so on with as many 'case/endcase' as
- ; needed
- default ;default is an optional 'case' that is
- ... ; carried out if no other cases are true
- endcase ;end of 'default' case
- ENDSWITCH ;mandatory 'end of switch' statement
-
- If $MENUSELECTION was equal to 1 (i.e. if the user had selected option 1
- from the menu) then ONLY the command(s) between "case 1" and its
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 8
-
-
-
- "endcase" would be executed. Note that "case 1" isn't fixed text. You
- won't always use "case 1", "case 2", etc. In some cases you might use
- this:
-
- case ".ZIP" ;is the SWITCH equal to ".ZIP"?
- endcase
- case 12345 ;is the SWITCH equal to 12345?
- endcase
-
- ...etc. Only the word "case" is fixed. Whatever follows the word "case"
- is compared to the variable specified in the SWITCH ($MENUSELECTION in
- this example) and if they're equal then the commands between that
- case/endcase are carried out. If they aren't equal, the case (to its
- ENDCASE) is skipped, and the next 'case' is checked.
-
- When you're ready for more information on using menus, see the
- MENUDEFINE, MENUBAR, MENUBOXH, MENUBOXV, IF and SWITCH in the DETAILED
- COMMAND SUMMARY section of SCRIPT.DOC. Also see SCRDEMO.SCR and
- POSTFILE.SCR for practical examples of menu and SWITCH usage.
-
- 1.10 Other Ways of Running Scripts
-
- The scripts you just wrote, as with any Icom script, can be executed in
- all sorts of different ways. You can run them from BIFs, from Jobs, from
- the DOS command line (using a .BAT file or menu system, for example),
- from another script, or from the Script Manager.
-
- 1.10.1 Running Script from BIFs
-
- Scripts can be executed from a BIF by simply specifying @SCRIPTNAME as
- the response to a prompt:
-
- | Your Logon Name> @HELLO Name . . . . . . st Name? Æ |
- ^^^^^^
- Another useful way to run a script from a BIF is via the "Connect
- Command" item on BIF screen 1. This command (or @SCRIPTNAME) is executed
- as soon as Icom connects to the BBS, before it gets any logon prompts.
-
- 1.10.2 Running Scripts from Jobs
-
- Scripts can also be executed by a job "Custom Command" (defined in the
- Icom Job Editor, where you define all your automated jobs) again by
- specifying @SCRIPTNAME as the Custom Command:
-
- | 12 Custom Command/Run script | CC: @MENU |
- ^^^^^
- The above two methods of running scripts allow you to run any script just
- about ANYWHERE during an automated job. Note that the .SCR extension is
- not specified in the examples above. You 'can' specify the extension if
- you like, but Icom supplies the .SCR extension if no extension is given,
- so it's just extra typing to add it (though it can add clarity to specify
- a .SCR extension). BIFs and Custom Commands are the only two places
- where you must specify '@' before the script name, and the reason for
- that is to tell Icom to run a script instead of doing what it usually
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 9
-
-
-
- does: send the text you define to the BBS.
-
- 1.10.3 Running Scripts from DOS
-
- Another way to run scripts is via the /scr: command line switch.
- Example:
-
- ICOM.EXE /scr:MENU
-
- This example above would cause Icom to switch to Terminal mode, run your
- MENU.SCR which we just created, display the menu (and handle any options
- in it, if there were real commands hooked up to the menu), then exit back
- to DOS as with the /run: command line switch, which does much the same
- thing, but for automated jobs instead of scripts.
-
- 1.10.4 Running Scripts from Scripts
-
- You can also execute a script FROM a script using the SCRIPT command.
- Example:
-
- SCRIPT "MENU" ;run MENU.SCR from another script
- print "Hello, World!"
- pause
-
- If you ran the above script, MENU.SCR would be executed (until
- completion... it could handle all sorts of different tasks) and when
- MENU.SCR finished, the message "Hello, World." would be displayed. (The
- Hello, World is simply used to show you that the original script
- continues execution after MENU.SCR finishes.) Again, you can add the
- .SCR extension if you like, but it's not necessary. Calling one script
- from another is not something many people will have to do, but the
- ability is there if needed.
-
- Note that no @ is required in either of the above examples when
- specifying the script name.
-
- You can also run scripts from scripts by calling up the Script Manager
- and allowing the user to hilight/Run one or more scripts, using the
- SCRIPT command but WITHOUT specifying a script filename after the
- command:
-
- pause "We interrupt this script to bring you the Script Manager..."
- SCRIPT ;the user could Tag/Run one or more scripts
- ; ...this script would continue below when all
- ; the other scripts were finished
- print "We now continue with our regularly scheduled program..."
-
- Note above that instead of using PRINT to print a message, and then PAUSE
- to wait for a keystroke, both were combined into a single PAUSE command.
- PAUSE accepts an optional message to PRINT before pausing.
-
- 1.10.5 Running Scripts from the Script Manager
-
- Of course, scripts can also be executed from the Script Manager by
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 10
-
-
-
- pressing [Alt-U] in Icom to access the Script Manager as you've just done
- (the Script Manager can also be used when online, by simply pressing
- [Alt-U] in Terminal mode... Again, it's on the [Alt-Z] terminal menu if
- you forget the key). You can also Tag and Run scripts one after another
- from the Script Manager, similar to what you can do with jobs from the
- Job Directory -- though this is useful only if the scripts you Tag/Run
- are DESIGNED to run one after the other. Further, Tagged scripts are
- executed in the ORDER IN WHICH THEY ARE DISPLAYED in the Script Manager,
- but you can easily change this order by renaming scripts (using symbols
- or numbers, like 1SCRIPT.SCR, 2SCRIPT.SCR, or !SCRIPT.SCR to sort to the
- top, etc).
-
- 1.10.6 Running Scripts via Function Keys
-
- And if the above isn't enough variety you can also "attach" scripts to
- function keys so a script executes when you press a key. This is best
- accomplished using Script Learn which asks you whether to attach the
- script to a function key or not. To attach a script to a key manually
- you must look in the Appendix of the SCRIPT.DOC manual (or in the online
- script help) for the "Key Code" of the function key, and must name the
- script using the numeric key code for the function key to attach to.
- Zeros must also be padded on the left side of the script name to make it
- exactly eight characters long. For example if you looked up the Key Code
- for the [F2] key you'd see that was 15360. To attach a script to the
- [F2] key then, you would name your script 00015360.SCR. From that point
- on, whenever you pressed the [F2] key from Terminal mode, 00015360.SCR
- would be executed.
-
- The leading zeroes MUST be added or the script will not execute when you
- press the key (this avoids conflicts with other scripts that just happen
- to use a number as the filename). Further you must use a function key
- (the key alone, or in combination with [Alt], [Ctrl] or [Shift] ... they
- all have unique Key Codes) and cannot use the [F1] key or any other keys.
- [F1] is reserved for online help and for future expansion.
-
- 1.11 It Can't be That Simple, Can It?
-
- Writing and using scripts can be as complicated or easy as you want it to
- be. There are many EXTREMELY easy-to-use script commands available to
- put loads of power into your hands with very little effort.
-
- To prove this point further, let's assume that you want to dial a BBS,
- make sure you're connected, perform a complete logon responding to every
- question asked by the BBS, keep an eye out for the BBS main menu so
- you'll know when the logon is complete, AND implement some sort of error
- handling so that if something goes wrong and you don't reach the main
- menu after, say, two minutes, you can give it up and hangup. To make it
- interesting, you also want to hangup if a BBS event is scheduled, and if
- you DO logon successfully, you want to capture BBS bulletin #5 to a file
- called BLT5.TXT, then logoff and hangup.
-
- If someone asked you to write a script to do this, what would you tell
- them? You'd probably tell them to get bent (or to use Intellicomm's
- built-in automation routines, which would make a lot more sense), but
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 11
-
-
-
- you'll be able to do this on most any BBS just a few minutes from now.
-
- It may seem a rather meaty assignment to be jumping to after "Hello,
- World", and with some script languages you'd be in for a rather
- complicated bit of script writing and concept learning to get the job
- done. With Intellicomm you get most of the work done with three
- commands: WHEN, SEND and WAITFOR. Here's the example (explanation
- follows the example):
-
- dial "Joe's BBS" 1 ;place the call
- offline goto ExitScript ;jump to label ExitScript: if not connected
- when "Enter Language #" send "1"
- when "graphics (Enter)=no?" send "N"
- when "st name?" send "John Smith"
- when "Password" send "Mypassword"
- when "Scan Message Base" send "N"
- when "More?" send "N"
- when "(Enter) to" send ""
- when "upcoming EVENT" goto HangItUp
- waitfor "Command? " 120 HangItUp
- ;the logon is now complete
- when ;clear all the whens, no longer needed
- cappush ;save capture filename/state (open/closed)
- capture "BLT5.TXT" ;open a new capture file
- send "B 5 NS" ;get bulletin 5, non-stop mode (PCBoard)
- waitfor "Command? " 120 HangItUp
- cappop ;restore the old capture file
- send "G" ;send [G]oodbye to logoff
-
- HangItUp: ; <-- here is where 'HangItUp' is
- hangup ;hangup the modem
-
- ExitScript: ; <-- here is where 'ExitScript' is
- exit ;end the script
-
- Just twenty lines gets the whole job done... and for demonstration
- purposes the above script is actually more involved than it need be.
- Ignore the technical details for now (you may still be wondering why
- there are double quotes around some items, etc.) and just take it one
- step at a time.
-
- The DIAL command (the first command in the script) is used to dial a BBS.
- The text following the dial command tells Icom which BBS to dial: in this
- example Icom would search your BBS Directory for a BIF with a description
- of "Joe's BBS", and if found it would Tag the BIF and "Dial" it. Note
- the '1' following "Joe's BBS". This tells DIAL that the BIF description
- must match exactly, and the '1' is optional. If the 1 is omitted, then
- any portion of any BIF description that had the text "Joe's BBS" in it
- ("Joe's BBS 2", etc) would also be tagged.
-
- Thus, you can also Tag/Dial multiple BIFs, depending on the descriptions
- you use to save your BIFs. If you had ten BIFs that had exclamation
- marks in their descriptions (Joe's BBS!, CRS!, Sound Advice!, etc), then
- you could just specify the exclamation mark, and omit the '1' following
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 12
-
-
-
- the description (i.e. do not force an exact match):
-
- dial "!"
-
- DIAL would then Tag/Dial all ten BIFs. When the BBS is connected to, it
- is untagged automatically. REDIAL can then be used to dial the tagged
- BBS's you haven't connected to, until all BIFs are untagged.
-
- The easiest way to find the proper text to use after the DIAL command
- ("Joe's BBS" above), if you intend to tag several BBS's by omitting the
- '1' in the DIAL command, is to enter Icom, press [Alt-D] to switch to the
- BBS Directory and select "Find" from the BBS Directory menu. Then enter
- the text you intend to use after the DIAL command ("Joe's BBS", without
- the quotes), select "Find all/Tag all", and Icom will show you which BIFs
- would be tagged if you used that text after a DIAL command. That's
- exactly what DIAL does: it changes to the BBS Directory, then does a
- "Find all/Tag all" on the text you followed the DIAL command with, then
- selects "Dial" from the BBS Directory menu. By using certain keywords
- (or exclamation points, etc.) in your BIF descriptions you can use this
- to your advantage to dial multiple BBS's with a single DIAL command.
-
- On to the next line: 'offline goto ExitScript'. Scripts execute from top
- to bottom (first line to last) unless told otherwise by specific
- commands: GOTO is one of those commands, and there are several others.
- The OFFLINE command checks the modem to see whether it's online or
- offline (connected or not connected). If the modem ISN'T offline (if we
- got connected), then Icom ignores the GOTO command and simply continues
- with the next line of the script. If the modem IS offline (we didn't get
- connected), then Icom executes the command following the offline command:
- GOTO in this case. I.e. an 'if' is implied before the OFFLINE command,
- and you can think of it as "if OFFLINE do this". GOTO causes Icom to
- goto (jump to) what is called a script 'label'. The label we're telling
- Icom to goto is label ExitScript:, which gets us down to the end of the
- script rather quickly (EXIT ends a script immediately). The only time
- you follow a label with a colon (:) is when you're actually showing Icom
- WHERE THE LABEL IS. I.e. where to GOTO. You don't follow labels with a
- colon anywhere else.
-
- I said GOTO causes Icom to jump TO the label, but that's not quite true:
- it jumps to the next line following the label. The label itself can't be
- executed, so that line is skipped and the script starts executing the
- line just following the label. If labels are found in the normal running
- of a script (we didn't GOTO the label; we just happened to run into it)
- the label is ignored, but any commands BELOW the label are still
- executed. If that's not what you want, then you simply put a GOTO above
- the label to to jump around the commands. For example, if the script
- above wasn't designed to logoff the BBS (we didn't want to hangup), we'd
- have to jump around the HANGUP command with a 'GOTO ExitScript' just
- above the label 'HangItUp:'.
-
- We could have just used 'GOTO HangItUp' in the OFFLINE command and
- eliminated the 'ExitScript:' label (the only place the 'ExitScript' label
- is used is by the OFFLINE command). But there'd be no need to hangup the
- modem if we were offline, so we put one label above the hangup, and can
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 13
-
-
-
- GOTO there to hangup and THEN exit the script, and one below the HANGUP
- so we can GOTO there and exit the script without hanging up. Using
- labels and GOTO's, etc., is how you perform decision-making in your
- scripts, causing some commands to execute under some conditions, and
- other commands (or no commands) to execute under other conditions. We
- also could have just used OFFLINE EXIT (if offline, exit the script...
- which is simpler than jumping to the label below), but two labels and a
- GOTO were used for demonstration purposes.
-
- The next command we run across after 'offline goto ExitScript' is the
- WHEN command. WHEN uses this format:
-
- WHEN "you find this text" do this
-
- ('you' referring to Icom, and 'find' meaning if the text comes in the COM
- port, from the BBS.) WHEN doesn't actually do anything on its own,
- unless you specify it all by itself, with no parameters following it, in
- which case it CLEARS all the WHENs defined previously. It's not until
- WAITFOR is executed that the WHENs become active: WHEN and WAITFOR works
- as a team. WHEN simply causes Icom to store the text and position of the
- command following the WHEN in memory, for later use with WAITFOR.
- WAITFOR activates all the WHENs (all prompts are then watched for
- simultaneously... you can use up to 19 WHENs at a time) while WAITingFOR
- specific text from the BBS. Waitfor uses this format:
-
- WAITFOR "wait for this text" <how long> <label to GOTO if not found>
-
- If the text "wait for this text" is found, the WAITFOR command ends and
- the script continues with any lines following the waitfor (above we SEND
- a command to get bulletin 5, open a new CAPTURE file, wait for the menu
- again, then reset the previous capture file and logoff). The 120 in the
- WAITFOR command in the script above tells WAITFOR how long to wait before
- giving up (in seconds; 120 is two minutes) and 'HangItUp' tells waitfor
- where to jump to (GOTO) if the text ISN'T found within the two minutes.
- 'HangItUp:', defined just below, skips the capture and executes the
- HANGUP command to hang up the modem, then it runs into the EXIT which
- ends the script. WAITFOR can also be used on its own, without WHENs, if
- you don't need any BBS prompts handled while waiting.
-
- If/when any of the text following any of the WHEN commands comes in from
- the BBS while a WAITFOR is active, Icom executes the command specified by
- that WHEN (and ONLY that command; none of the commands in the other WHENs
- are executed until the text they specify is found). If the command
- specified in the WHEN doesn't turn control over to another part of the
- script (SEND just sends some text; GOTO turns control over to another
- part of the script), then Icom just executes the command and continues
- waiting for the text specified in the WAITFOR. If/when the text
- specified by another WHEN is found, the same thing happens, and control
- returns to WAITFOR until the timeout is reached. I.e. the WHENs are just
- a temporary diversion while WAITingFOR the main objective: the main menu.
- The WAITFOR timer is not reset after executing the WHEN commands. Two
- minutes in total, no matter how many times we execute WHEN commands, is
- how long WAITFOR will wait. I say "wait" because no other commands
- (other than the WHENs) in the script can execute until the WAITFOR either
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 14
-
-
-
- finds the text or times out. I.e. WAITFOR pauses script execution, and
- the lines below a WAITFOR cannot execute until either the text is found,
- or WAITFOR times out.
-
- The commands used in WHEN statements are just regular Icom script
- commands, and you can use any script command (or even a set of commands
- if you use SWITCH, or IF/ENDIF, etc) with a WHEN. The SEND command, used
- in most of the WHENs above, sends responses to the BBS (no different than
- you typing the response at the keyboard).
-
- Send can also be used on its own to simply send a few commands to the
- BBS. Send automatically adds a carriage return (same as pressing the
- ENTER key) after the text, so you needn't worry about adding one
- yourself:
-
- send "J 2" ;PCBoard, join conference 2
- send "D" ;PCBoard [D]ownload command
- send "ICOM201A.ZIP" ;filename to download
- download "Z" ;download the file using Zmodem
-
- The example above probably doesn't even need an explanation other than
- the "Z" following the DOWNLOAD command. When downloading (or
- uploading... UPLOAD is the command in that case), to select a protocol,
- you specify the same letter that you'd press to select the protocol from
- Icom's protocol menu. If you pressed [PgDn] in terminal mode, you'd see
- that "Z" is the hotkey used on the protocol menu to select Zmodem. So
- "Z" is what you specify after the DOWNLOAD command in your script to use
- the Zmodem protocol. You can use other protocols (including any external
- protocols you have set up) in the same way; simply by specifying the
- protocol menu hotkey after the DOWNLOAD command. You could also do this
- with a WHEN:
-
- WHEN "Start your download" DOWNLOAD "Z"
-
- If/when the text "Start your download" came in from the BBS during a
- WAITFOR, Icom would begin a Zmodem download.
-
- Zmodem doesn't require the name of the file to download since the
- protocol itself (Zmodem at the BBS) passes the filename. The above
- DOWNLOAD command could even perform a 'batch' Zmodem download, since all
- the logic to perform multiple-file downloads is built into the protocol.
- No filenames need ever be specified when downloading with Ymodem OR
- Zmodem; the filename(s) are specified by the sender. Xmodem and its
- cousins Xmodem-1K and Xmodem-1k-G do require a filename, since the Xmodem
- protocol wasn't designed to pass filenames. Further, since Xmodem
- doesn't pass the filename it cannot perform multiple-file (batch)
- downloads. If using an EXTERNAL protocol it's up to you to know whether
- the protocol requires a filename on downloads (if it does require a
- filename, the name is specified immediately following the protocol
- letter; Icom will pass the filename to the protocol). *ALL* protocols
- require filenames for uploads:
-
- UPLOAD "Z" "ICOM201A.ZIP" "ICOM201B.ZIP"
- UPLOAD "Y" "*.ZIP" "D:\TEMP\A???.*"
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 15
-
-
-
- The first command would upload ICOM201A.ZIP and ICOM201B.ZIP, using
- Zmodem. The second would upload any files with a ZIP extension (anywhere
- on the Icom 'Upload PATH' defined in the main setup or current BIF), and
- any file in the D:\TEMP directory with an 'A' followed by any 3
- characters, and any extension. [Regular DOS wildcards... check your DOS
- manual if you aren't familiar with wildcards.] Again, you can only
- specify multiple filenames with Ymodem (or Ymodem-G) and Zmodem, or an
- external protocol that supports 'batch' uploads. Xmodem does not
- support batch uploads or downloads.
-
- You can also create a 'list' of filenames using the Text Editor, then
- have the protocol use the list to get the filenames to upload:
-
- UPLOAD "Z" "@FILES.TXT"
-
- Zmodem would read FILES.TXT, and upload all filespecs on the list. Each
- filespec may contain a drive/path, and may use wildcards. When using
- text lists, you specify each filespec on a separate line of the file:
-
- C:\TEMP\SOMEFILE.ZIP
- A???.*
- *.ZIP
-
- Note that these rules also apply when uploading manually... you can do
- all of the above (minus the quotes) when specifying filenames at the
- Upload filename prompt.
-
- 1.12 Variable Overview
-
- Variables are a very useful script feature, and can increase the
- usefulness and flexibility of your scripts significantly. They're not
- something you 'have' to know about to write scripts, but are something
- you probably will WANT to know about, since they're extremely useful.
-
- Variables are nothing more than "places to put things". Some variables
- come with 'things' already in them (information which you can use in your
- scripts), while other variables are created by you (via the VARIABLE
- command) to allow you to keep track of your own 'things'.
-
- If you wish to count something, such as the number of times a certain
- error happened, a variable is needed. If you wish to know what time it
- is, you use another variable. There are six different types of variables
- you can make use of in your scripts, and only a quick overview of
- variables is given in this section. Detailed information on all six
- types of variables, plus many examples of usage, can be found in section
- 4 below.
-
- System Variables
- ~~~~~~~~~~~~~~~~
- All System Variables begin with a dollar sign ($). They are used to
- access all sorts of information about your computer system, and the
- current status of Intellicomm itself. They also make your scripts much
- more flexible, since they allow you to avoid specifying constant data.
- Examples:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 16
-
-
-
- SEND $PASSWORD ;send the BIF logon password
- PRINT $DATE ;prints the current date
- IF $DOW = 1 PRINT "Today is Sunday" ;$DOW is the Day-Of-Week
- IF $DOW = 2 PRINT "Today is Monday" ; ...etc.
-
- The first IF means 'if the day-of-week ($DOW) is equal to 1 (Sunday)',
- then PRINT "Today is Sunday". If $DOW is NOT 1, the PRINT following the
- IF is ignored.
-
- There are a hundred or so different System Variables available and all
- are outlined quickly in the SCRIPT COMMANDS AT A GLANCE section, and (in
- more detail) in an appendix at the end of the SCRIPT.DOC manual. Anyone
- and everyone can and should use System Variables... they're very
- straightforward and useful. As with all the other types of variables
- listed below, you can use a System Variable in ANY script command that
- takes a parameter, instead of using constant text or a constant number.
-
- User-Defined Variables
- ~~~~~~~~~~~~~~~~~~~~~~
- These are variables you define yourself using the VARIABLE command. If
- you wish to count something, you might define a variable called 'count':
-
- VARIABLE count ;this command defines variable 'count' and
- ; assigns 0 to it (0 is the default)
- VARIABLE ten 10 ;this command defines variable 'ten' and
- ; assigns 10 to it.
-
- INC count ;INCrement count (count = count + 1)
- ADD count ten 5 ;count = 10 + 5
-
- If you wish to store your name, you might use this:
-
- VARIABLE LogonName "John Smith"
-
- Later in your script, instead of using SEND "John Smith", you could use
- SEND LogonName. These variables also allow you to avoid 'hardcoding'
- information into your scripts, and thus they allow a single script to
- serve more than one purpose.
-
- Instead of DIAL "Joe's BBS", you can get user input from the keyboard,
- store the input in a variable, then use the exact same script to dial
- multiple BBS's. Further, these variables also make your scripts easier
- to maintain. If you define all your variables in one section of the
- script, and later something changes (a BBS prompt, for example), you can
- simply change the value assigned to the variable without having to change
- dozens of WHEN commands. "Variables" are also what enables Intellicomm
- to automate calls to different BBS types. It simply loads the BIF
- information into its variables... and the program then behaves
- differently, since it's using different data.
-
- Many script commands also REQUIRE a variable as the first parameter, in
- order to store the results of an operation. For example the ADD command
- adds two numbers and stores the result in a User-Defined Variable. The
- GETS command gets input from the keyboard, and also stores the input in
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 17
-
-
-
- any User-Defined Variable:
-
- VARIABLE myvariable ;define a variable called 'myvariable'
-
- GETS myvariable 60 ;get (max) 60 characters from the keyboard, store
- ; the input in 'myvariable'
- PRINT myvariable ;print the result
-
- User-Defined Variables exist only from the time of their creation with
- the VARIABLE command until the current script ends. They are also
- 'local' to the current script, so if you execute another script FROM a
- script with the SCRIPT command you needn't worry about changing the
- contents of the variables in the first script.
-
- The Global Variable Array (GlobalStr)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This is a variation of the User-Defined Variables. But the 'Global'
- Variables exist in memory for the duration of the Icom session. Unlike
- the User-Defined Variables, these variables are 'globally' available to
- all scripts, and still hold their values after the script ends (used
- mainly for inter-script communication and the like). They also employ a
- concept known as an 'array'.
-
- The GlobalStr array is where script command line parameters are stored,
- if you pass parameters to a script from a BIF command, or job Custom
- Command, or from the DOS command line. Use of the GlobalStr array is
- more advanced than most other script concepts and will probably only be
- needed by advanced script writers.
-
- BIF Variables
- ~~~~~~~~~~~~~
- These variables allow you to access any information from the BIF
- currently in use (the BBS you're currently connected to, or the BIF you
- explicitly load with the LOADBIF command). BIF variables are also
- somewhat advanced and probably won't be needed immediately. See the BIF
- VARIABLES section in SCRIPT.DOC when you're ready for more information.
-
- Main Setup Variables
- ~~~~~~~~~~~~~~~~~~~~
- These variables allow you access any information from the INI
- (INItialization file) currently in use; normally ICOM.INI (you can also
- load Main Setup files with the LOADINI command). The Main Setup
- Variables contain all the main data you define in the Intellicomm Setup.
- Again, these variables are somewhat advanced and you can leave them for
- the time being. When you're ready for more information, see the MAIN
- SETUP VARIABLES section in SCRIPT.DOC.
-
- Permanent Variables
- ~~~~~~~~~~~~~~~~~~~
- Permanent Variables make use of the script "File Input/Output" commands
- to store information on-disk. The concepts aren't overly difficult to
- grasp, but again won't be needed by everyone. See the INTRODUCTION TO
- FILE INPUT / OUTPUT, here in SCRTUTOR.DOC, when you're ready for more
- information.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 18
-
-
-
- 1.13 A Word on Formatting
-
- You may have noticed above in some of the example scripts that certain
- items 'lined up' with each other (the SEND commands after the WHENs, for
- example), and that the comments are in a certain position, etc. But this
- is done only to please the eye, and the only rules that are forced on you
- as far as formatting goes are these:
-
- 1. Every script command (including any parameters that follow the
- command) must be on a separate line. EXCEPTION: If the script command
- is designed to take another command as one of its parameters (such as
- the OFFLINE and WHEN commands demonstrated above), then you may (and
- must) place more than one command on a single line. Just don't try to
- do this:
-
- dial "Joe's BBS" offline exit ;both on the same line
-
- If a command accepts another command as a parameter, the Detailed
- Summary of the command will tell you so. If a command isn't expected as
- a parameter, you can't use one.
-
- 2. At least one space or TAB character must separate the script command
- from the parameters (if any), and at least one space/TAB must separate
- each parameter. Example: COMMAND "parameter 1" "parameter 2" ...
- These are errors: COMMAND"parameter1" or COMMAND "parm1""parm2".
- ^ ^
- One or more spaces (or a TAB) are needed where the carets (^) are.
-
- 3. Only the first 256 characters of each line are used by the script
- processor. You may create lines that are longer than 256 characters
- (comments that go past the 256 character mark, etc.), but only the
- first 256 characters are significant to the script processor. This
- will probably only be relevant when using the MENUDEFINE command,
- which uses the format: MENUDEFINE "Menu Item 1" "Menu Item 2" ...
- etc. You'll have to make sure to fit all your menu items in the first
- 256 characters for it to work properly. If you run into problems, use
- variables instead of literal strings and use short variable names.
- Example:
-
- VARIABLE i1 "Menu Item ~1"
- VARIABLE i2 "Menu Item ~2"
- ... ; "..." denotes more of the same
- MENUDEFINE i1 i2 ...
-
- 4. Script 'labels' used to define where a GOTO (and GOSUB) should jump to
- must on a line by themselves, must be followed by a colon, and there
- must not be any spaces or tabs anywhere in the label right up to the
- colon. The only characters you can use in labels are A-Z, a-z, 1-9,
- and the underscore (_). Labels are not case-significant (LABEL: is
- the same as label:). NOTE: comments are permitted after labels, but
- you must put at least one space or TAB between the label and the
- comment. Example:
-
- HangItUp: ;this label HangItUp
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 19
-
-
-
- 5. Comments must be preceded by a semicolon (;) and may appear on the
- same line as a script command or label (after the command/label and
- all parameters), or may be placed on a line by themselves. Comments
- must also be separated from the command/parameters by at least one
- space or TAB. These comments are invalid:
-
- HangItUp:;This comment isn't separated from the label
- dial "Joe's BBS";This comment isn't seperated from the parameter.
-
- These comments are fine:
-
- HangItUp: ;This is fine with a space
- dial "Joe's BBS" ;This is fine with a space
-
- All characters following a semicolon (to the end of the line) are
- ignored by the script processor. The one exception to this is if the
- semicolon is inside quotes.
-
- 1.14 Why the Double Quotes ""?
-
- Double quotes, such as the quotes surrounding the text after the WHEN and
- SEND commands above are used (a) to keep all the text together as a
- single unit/parameter, (b) to allow you to use text between the quotes
- that would otherwise 'mean' something to the script processor
- (semicolons, for example, which cause Icom to ignore the rest of the
- line, and spaces or tabs which signify the end of the parameter), and (c)
- to tell the script processor that it's dealing with literal text instead
- of a variable. Variable names are never put in double quotes.
-
- A quick note: if the text you're putting between the double quotes has
- one or more double quotes IN it, then you must 'escape' the double quote
- with a caret. Example:
-
- "This text has ^"double quotes^" in it"
-
- Quotes are never used to surround script commands or labels. They're
- only needed in the parameters (if any) following script commands, and
- only if the parameter is specifying constant TEXT (as opposed to a
- variable name, or a constant number containing only characters from 0-9).
-
- 1.15 Specifying Control Characters
-
- To specify a control character in a script command parameter (backspace,
- carriage return, escape, line feed, form feed, Ctrl-A, Ctrl-B, Ctrl-C,
- etc., are 'control characters') simply precede the control character with
- a caret (^). For example, Ctrl-A would be specified as "^A", Ctrl-B is
- "^B", escape is "^[". Refer to the ASCII table in the appendix of
- SCRIPT.DOC (or in the online help) for the complete list of control
- character codes. Here's an example of sending two escape characters to
- the BBS (SENDNC sends without adding a Carriage Return. The NC means
- 'N'o 'C'arriage Return):
-
- SENDNC "^[^[" ;SENDNC doesn't add a CR as SEND does
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 20
-
-
-
- If you have to use a caret (^) for some reason, you must use TWO carets
- or the script processor will either ignore it (if used alone), or will
- convert the next character to a control character:
-
- PRINT "^^" ;print a single caret
-
- To enter the control character ^^ (ASCII code #30), hold down the [Alt]
- key and type 3 then 0 on the NUMERIC KEYPAD, then release the [Alt] key.
-
- 1.16 Tildes
-
- You can cause a one second pause between characters with SEND/SENDNC, or
- SENDNP/SENDNPC by using a tilde (~):
-
- SENDNC "^[~^[" ;send ESC, delay for 1 second, send another ESC
-
- A delay is almost ALWAYS required by BBS front ends which require you to
- press ESC twice before logging on. For some reason, they don't seem to
- accept two rapid ESCapes. Again if you want to send a tilde, escape it
- with a caret:
-
- SENDNC "^~" ;sends a tilde (~)
-
- Tildes are only relevant (and need only be escaped with ^) when you use
- them with SEND/SENDNC or SENDNP/SENDNPC (i.e. when sending data out the
- COM port). You needn't and shouldn't escape tildes with a caret in any
- other script commands.
-
- TIP: If you're thinking of writing logon scripts to use in your automated
- jobs just for this purpose of sending ESC characters to bypass a BBS
- front end, it is not needed. Just specify the ESCapes in the BIF
- "Connect Command" option on the 1st BIF screen:
-
- | Dial Prefix . . Connect Command ^[~^[
- |
-
- The above Connect Command causes Icom to send an ESC, pause for one
- second, then send another ESC as soon as it connects to the BBS. This
- should get you by most all BBS front ends.
-
- 1.17 Specifying Numbers
-
- When specifying constant numbers in scripts (i.e. in math operations, or
- when a number is expected as a parameter as with the timeout in WAITFOR)
- you needn't and shouldn't put quotes around the numbers:
-
- GOTOXY 1 1 ;move the screen cursor to the top left corner
-
- Why? Well, numbers never use quotes or semicolons or spaces in them as
- constant 'strings' (text) might, and they never conflict with variable
- names since you can't specify a number as the first character of a
- variable name.
-
- Further, you must not use symbols or commas in the number, unless the
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 21
-
-
-
- parameter is to be used as a 'string' and is in quotes (i.e. if using it
- in a PRINT or WHEN or other command that takes TEXT as a parameter rather
- than a number). As soon as the script processor finds a non-numeric
- character in a parameter -- when it's expecting a NUMBER as a parameter -
- - it ignores all following characters:
-
- ADD result $5.00 $10.00 ;this causes an error, since $ signifies
- ; a System Variable. Icom would look for
- ; System Variables called 5.00 and 10.00
- ; ...wouldn't find them, and would abort
- ; the script with an error.
- ADD result "50.5" 30 ;'result' will be 50 + 30 (the quotes are
- ; stripped, the "." is not a number and is
- ; thus ends the 1st number)
- PRINT "$5.00" ;text is expected by PRINT, and is in quotes,
- ; so this is fine
- ADD result 2,000 3,000 ;'result' will be 2 + 3 due to the commas
- WHEN "2,000" send "3,000" ;text is expected by WHEN and SEND, and is in
- ; quotes, so this is fine
-
- This version of the script language automatically strips quotes from
- numbers if you use them... so this is 'legal':
-
- GOTOXY "1" "1"
-
- But the above is not good programming practice and isn't a good habit to
- get into. Most programming languages consider it an error to put
- constant numbers in quotes, since numbers are stored differently by
- computers than text/strings are. You should get into the habit of
- leaving the quotes off when specifying constant numbers, even though it
- really makes no difference to this version of the script language.
-
- 1.18 Numeric Limits
-
- Constant numbers (or numbers stored in variables that you plan to use in
- place of a constant number) are limited to the range:
-
- -2147483648 to 2147483647
-
- That's about two billion negative and positive. The limits may look like
- they were picked from a hat, but believe it or not those are 'round'
- numbers to the computer. Computers don't count in decimal (base 10) like
- we do, so you'll rarely find a number rounded to the nearest 10, 100,
- etc. The above are the limits of a four "byte" (32 bit) digit. If you
- go past the limit in either direction (i.e. add, subtract, multiply or
- divide numbers that end up with a result higher or lower than the limits
- above), the result will not be valid.
-
- 1.19 Compound Statements
-
- Compound Statements, while the term might sound scary, are simply groups
- of script commands on more than one script line, that 'act' similar to a
- single script line. Three commands allow compound statements, and each
- of the three has a 'closing' command to signify the end of the compound
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 22
-
-
-
- statement:
-
- Command Closing Command
- ---------------------------------
- IF ENDIF
- SWITCH ENDSWITCH
- WHILE ENDWHILE
-
- Here's an example:
-
- variable x
- variable y
-
- IF x = y
- print "x is equal to y"
- pause "Please press a key..."
- return
- ENDIF
-
- You'll notice above that three commands were placed between the IF and
- ENDIF. If the comparison turned out to be TRUE (if x was equal to y),
- then all three commands would be executed. If the comparison turned out
- to be FALSE (if x was NOT equal to y) then everything between the IF and
- ENDIF is skipped.
-
- You can also "nest" compound statements, or in other words you can place
- compound statements INSIDE of other compound statements like this:
-
- IF x > y ;is x greater than y?
- IF x = 0
- print "x is equal to zero"
- return
- ENDIF ;end of the second IF
- WHILE x > y
- print x
- dec x ;DECrement (x = x - 1)
- ENDWHILE ;end of the WHILE
- ENDIF ;end of the first IF
-
- The first IF above works in exactly the same way as the first example.
- If x is greater than (>) y then the commands between the first IF/ENDIF
- pair are evaluated. If x is NOT greater than y, then everything is
- skipped right down to the last ENDIF. There is no limit as to how many
- compound statements you can nest, and the second IF above could have
- another IF, SWITCH or while before its ENDIF, and so forth.
-
- It's important to understand that these compound statements ACT as a
- single script command, for cases such as these:
-
- ONLINE SWITCH next_job
- case 1
- gosub do_job_1
- endcase
- case 2
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 23
-
-
-
- gosub do_job_2
- endcase
- ENDSWITCH
-
- Above if the modem WAS online, then the SWITCH compound statement (to the
- ENDSWITCH, executing one or none of the 'cases') would be evaluated. If
- the modem WASN'T online, then the entire SWITCH (along with any nested
- compound statements WITHIN the SWITCH/ENDSWITCH) is ignored. This is
- also legal:
-
- ONLINE IF x = y SWITCH
- ... ;CASE/ENDCASEs here, along with even more
- ... ; compound statements if need be
- ENDSWITCH
-
-
- Note that if a command is specified after the IF comparison (after 'x =
- y' above), then it is assumed that you are using the stand-alone version
- of IF, instead of using an IF/ENDIF compound statement. Example:
-
- IF x = y PRINT "x = y"
-
- IF x = y
- PRINT "x = y"
- ENDIF
-
- Both of the above do the same thing... One uses the stand-alone IF
- variation (where only one command, or a compound statement is accepted
- after the comparison) and one uses the IF/ENDIF variation. In the
- previous example, the SWITCH is legal after the IF comparison since
- compound statements (and nested compound statements) behave like single
- script commands. Thus, if the modem was NOT online then everything right
- to the ENDSWITCH would be skipped. If the modem WAS online then the IF
- would be evaluated... and again if x was NOT equal to y, then everything
- to the ENDSWITCH would be skipped. If x WAS equal to y, then the SWITCH
- would be evaluated. Nested commands (compound or otherwise) progess one
- step at a time, and whenever something proves to be false, the very next
- command, be it a single command, a compound statement, or multiple nested
- compound statements, is skipped.
-
- Only after you gain a bit of experience will you want to get into
- compound statement nesting, but you're bound to run into it sooner or
- later (and it certainly can be quite useful at times) so it's handy to
- know how they work.
-
- 1.20 Where To Go From Here
-
- Congratulations! This ends the introduction. You could quit with this
- knowledge right now and write some very useful scripts indeed. You know
- what scripts are, how to write them, how to run them in every way
- imaginable, how to display information on the screen, including working
- menus, how to dial a BBS, how to watch for BBS text/send responses, how
- to perform error handling if key BBS text you're looking for isn't found,
- how to upload and download files, how to hangup the modem, how to perform
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 24
-
-
-
- basic decision-making (GOTO), how to define and use variables, and in
- general how to use compound and nested compound statements! And you
- should be able to accomplish just about anything with these skills.
-
- There are many more script commands in Icom's script language not
- demonstrated above that are just as easy to learn and use, just as
- useful, and will require little explanation to use. If you understood
- the examples above you'll have no trouble understanding most of the other
- script commands... It's only a matter of time and hands-on experience
- until you master scripts completely. And when you master scripts, a
- whole new world of possibilities will open up to you!
-
- Your next step should be to execute the SCRDEMO.SCR (script demo) script
- if you haven't already, and to then "Edit" SCRDEMO.SCR to see how various
- tasks were accomplished. When you see a command you're not familiar
- with, either use the online help "SCRIPT.DOC" link, or the File Viewer
- (accessable in the Editor via the File|DOS/Open... menu option) to look
- up the detailed summary of any commands you don't understand, or simply
- want to read up on.
-
- All script commands and System Variables are outlined in the SCRIPT
- COMMANDS AT A GLANCE section of SCRIPT.DOC, and each command is explained
- in detail in the DETAILED COMMAND SUMMARY section. EXAMPLES of usage for
- each command can also be found in the Detailed Summaries.
-
- 1.21 The Secret to Success
-
- The only real problem you have when writing scripts is in remembering the
- commands, and remembering what 'parameters' follow the commands (like the
- "Z" after the DOWNLOAD command). The trick is to ONLY concentrate on the
- commands you NEED, and to learn (then USE) only one or two commands at a
- time. Practice makes perfect; take one or two script commands that you
- need, practice with them and get a script WORKING with them, and only
- then move on to other commands you may need. You WILL succeed if you
- take this approach.
-
- Most people will use only 5% or 10% of the script commands, and will
- never bother the other 90% (though 'which' 10% of the script language
- each user concentrates on varies from person to person, depending on
- their needs) so don't bother with a command until you need it. Perhaps
- start with WHEN and SEND, to define your own logon script (note that you
- MUST define a password in your BIF or Icom will not attempt an auto-
- logon). Practice calling the logon script from a BIF by placing
- @SCRIPTNAME in the BIF "Connect Command" item on BIF screen 1:
-
- | Dial Prefix . . 1 Connect Command @SCRIPTNAME |
-
- SCRIPTNAME.SCR would be executed as soon as Icom makes a connection at
- that BBS. Try getting the script to answer just one or two logon
- questions such as your name and password ... get that working, THEN move
- on to other things. Or you could practice running a script from one of
- the BIF Logon responses:
-
- | Your Logon Name> @SCRIPTNAME Name . . . . . . st Name? Æ |
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 25
-
-
-
- SCRIPTNAME.SCR in the example above would start with:
-
- SEND "John Smith"
-
- since Icom would already have found the "st Name?" prompt ... The script
- might then continue to define some WHENs to handle other logon prompts:
-
- WHEN "dots will echo)?" SEND $PASSWORD ;sends the BIF password
- WHEN "last read" SEND "N"
- WAITFOR "Command?" 120
-
- Icom will pick things up wherever your script leaves off (assuming the
- proper BIF Logon information is defined). You can run a script to answer
- a SINGLE logon prompt, or you can handle the entire logon (even carrying
- out a side-job such as capturing the BBS news file, etc.) and leave Icom
- at the BBS Main Menu. The same applies to mail runs, bank transactions,
- file transfers, etc. You can execute a script in ANY BIF response slot.
- As long as the script carries out (at minimum) what the internal BIF
- command its replacing did (opening a DOOR, etc), you should be fine.
-
- Only when you become familiar with these basic concepts and gain
- experience should you move on to more complex scripts (if you want to
- learn more... stop whenever you're satisfied with what you've learned).
- Browse the SCRIPT COMMANDS AT A GLANCE section often in the beginning,
- just so that you'll at know what commands ARE AVAILABLE for specific
- tasks. Don't try to memorize any commands... just give it a quick browse
- so you'll know, in general, what is available. Only when you NEED that
- task done in a script will you have to bother learning how the command
- actually works. Imagine the script language as a big plate of assorted
- appetizers, meant to serve everyone: look the plate over (the SCRIPT
- COMMANDS AT A GLANCE section), and take what you want.
-
- With just a little time and experience, you'll be able to write very
- powerful scripts that will AMAZE you and give you great satisfaction.
- Enjoy yourself, and be proud of your accomplishments! Writing scripts
- that WORK, no matter how insignificant the task, can be a very satisfying
- way to spend an evening or two.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 26
-
-
-
- 2. WHAT HAPPENS WHEN A SCRIPT ENDS?
-
-
- The short answer to what happens when a script ends is, "hopefully the
- right thing, for whatever circumstances the script left the system in".
- The longer answers follow:
-
- Scripts end when one of four things happen: (1) the end of the script is
- reached (there are no more commands to execute; this is true even if a
- subroutine was executed and you forgot to add a RETURN), (2) Icom runs
- across an EXIT or RETURN or SYSTEM command in a script, which ends the
- script at that point, (3) the connection is lost and Icom was running an
- automated job prior to calling the script, (4) the user aborts the script
- by pressing [Alt-Q] then selecting "Abort Job/Script" or "Abort Script
- Only" from the control menu. If the user selects "Abort Job/Script" then
- both the script and the automated job are cancelled.
-
- When any of the four events above occur, what Icom will do next depends
- on whether your modem is connected or not connected (online or offline),
- where you called the script from, and whether an 'errorcode' was returned
- by the script in the EXIT or RETURN command.
-
- If you run a script from an automated job via a Custom Command, the first
- thing Icom will do when the script ends is attempt to locate its position
- on the BBS by sending the BIF "General Menu Exit" command, then watching
- for a BBS menu (the script may have changed locations, so Icom can't
- assume it ended up where it was when the script started). If Icom
- successfully locates its position, the next job task continues (Get Mail,
- etc., or perhaps even another Custom Command that runs another script).
-
- If you call a script from a BIF, by using @SCRIPTNAME in one of the BIF
- command responses, Icom expects that YOU have made sure that your script
- did the appropriate thing, and left Icom in the location it needed to be
- in for whatever it'll be doing next (the same as any command you define
- in a BIF; you can define anything you want, but if it doesn't do the
- right thing, your job will probably fail).
-
- If you call a script from the Script Manager, after the script stops
- running Icom checks to see whether you're online or offline, and if
- online it leaves you in Terminal mode to continue with your BBS session.
- If the modem is offline when the script ends, Icom returns to the Script
- Manager (unless you originally entered the Script Manager from Terminal
- mode using [Alt-U] ... in that case, as with most 'sub-tasks' you execute
- from Terminal mode, you are returned to the terminal when the script
- ends).
-
- If you run a script from DOS via the /scr: command line switch:
-
- ICOM.EXE /scr:MYSCRIPT
-
- Icom automatically returns *to DOS* if the modem is OFFLINE when the
- script ends; but not until processing ALL command line switches. This
- command is legal:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 27
-
-
-
- ICOM.EXE /scr:MYSCRIPT /run:"Some automated job"
-
- Icom would run the script, then the automated job, and THEN if the modem
- was offline it would return to DOS (note that Icom always saves /Run:
- switch until ALL other command line parameters are processed. If you put
- the /run: first, and the /scr: second, the script would still be executed
- first). If you do something like the above, your script would have to
- perform the dialing/logon, and would have to either leave Icom connected
- to the BBS that the job is set up to run on, or would have to HANGUP
- before exiting so that the job would dial. If Icom is connected when a
- job is started it assumes you've already connected to the proper BBS and
- simply begins the job without dialing. If you aren't connected to the
- proper BBS, the job will probably fail.
-
- This is also legal:
-
- ICOM.EXE /scr:"SCRIPT1 parm1 parm2" /scr:"SCRIPT2 parm1 parm2"
-
- (See section 4.10 for more information on passing parameters to scripts.)
-
- If the modem is ONLINE when the script ends (rather, when all command
- line options are processed) then Icom switches to manual terminal mode.
- If the modem is OFFLINE, Icom exits back to DOS. If you're designing a
- script to be called with the /scr: command line option via a .BAT file or
- menu system (or Windows/DESQview), make sure that you execute the HANGUP
- command before exiting your script, if you want Icom to exit back to
- where it was called from (back to DOS, the .BAT file, or menu system).
-
- 2.1 EXIT and RETURN Error codes
-
- If you use an EXIT or RETURN command in your script, and specify a
- negative number as the exit code (EXIT -1, EXIT -2, RETURN -1, RETURN -2,
- etc), then Icom cancels all automated jobs, hangs up, and returns to
- whatever called it (the Job Directory/Main Menu if an automated job, the
- Script Manager if called from there, or DOS if called via the /scr:
- command line option). Using a negative exit code after EXIT or RETURN is
- a rather potent option that should only be used when the circumstances
- warrant it.
-
- If a positive number follows the EXIT or RETURN command (EXIT 1, EXIT 2,
- RETURN 1, RETURN 2, etc.) then Icom removes the current BIF from the job
- queue, hangs up, and won't carry out any further jobs on that BBS (if
- multiple jobs were Tagged for the current BBS) during the current
- automated session. Use this one when you run out of time at a BBS, or an
- EVENT is scheduled, etc., and you don't want to call that BBS back.
-
- If zero (0) or no error code is specified after the EXIT or RETURN
- command (EXIT 0, RETURN 0, or just EXIT or RETURN alone), or the script
- simply reaches the end without any EXIT/RETURN at all, then it's a
- regular exit and the the usual rules that govern what happens when a
- script ends (outlined above) apply. This is what will be used in 99% of
- the cases to end a script.
-
- NOTE: This only applies to the RETURN command when it's used to actually
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 28
-
-
-
- exit a script: I.e. if the RETURN is found OUTSIDE of a subroutine (a
- GOSUB command was not executed previously). If you're simply RETURNing
- from a subroutine, error codes are ignored. EXIT is used to exit all
- scripts (if you call a script from a script and want to abort BOTH
- scripts) while RETURN is used to simply exit the current script back to
- the caller.
-
- 2.2 Using the HANGUP Command for Error-Recovery
-
- If your script is called by an automated job (Custom Command or BIF
- command) and loses track of its position or just can't get out of a
- tricky situation, the easiest way to recover is to execute a script
- HANGUP command. This will cause the modem to hangup, and when the
- connection is lost Icom will abort the script, notice the carrier loss
- (if during an automated job) and will call the BBS back if any job tasks
- remain unfinished. Losses of connection are tracked by Icom, and it will
- only permit *three* losses of connection before removing the BIF from the
- job queue. If you use the HANGUP command from a script during an
- automated job, it simply looks like a regular loss of connection to
- Intellicomm.
-
-
- 3. INTRODUCTION TO SUBROUTINES (GOSUB)
-
- Subroutines are indespensible in any programming language. They allow
- you to carry out complicated tasks with a single script command -- GOSUB,
- short for "GO" to "SUB"routine. Subroutines are also useful in cutting
- down on programming/typing errors, since you can write and debug a
- routine ONCE, then make use of that same bug-free routine in several
- places in the script. Without subroutines you would be forced to write
- repetitive sequences of script commands multiple times, thus increasing
- the chance of making a typing error, or introducing a bug.
-
- 3.1 When to use a Subroutine
-
- Subroutines should be used to replace repetitive sequences of script
- commands. For example, if you're doing something like printing a 'Press
- a key' message, then clearing the screen, you might as well use a
- subroutine to avoid repeating the exact same commands in multiple places
- in the script:
-
- PressAKey:
- PAUSE "Press a key... " ;wait for a key press
- CLS ;clear the screen
- RETURN ;return from the subroutine
-
- Once the subroutine is in place, whenever and wherever you need to pause
- for a keypress in your script, you just execute the command:
-
- GOSUB PressAKey
-
- When the script processor runs across a GOSUB command it first saves its
- current position in the script (the position of the GOSUB command), then
- it does the equivalent of a GOTO (jumps to the label specified after the
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 29
-
-
-
- GOSUB) and begins executing the script at the next line after the label.
- When a RETURN statement is found, it then restores the position it saved
- previously, and continues running the script at the next line below the
- GOSUB command.
-
- Subroutines can also be used to make a script easier to follow and thus
- easier to maintain (add to) and debug. They can also help you to
- organize your thoughts when you have a complex task to accomplish.
- Instead of trying to figure out how you're going to fit a complicated set
- of commands into the EXISTING structure of your script, you can instead
- write the complicated code elsewhere (concentrating only on one task at a
- time) in a subroutine, without making a mess of the existing structure of
- your script.
-
- Finally, you can also do the equivalent of inventing new script commands
- with subroutines. Computer (and script) languages give you "building
- blocks" in the commands they provide. You won't always find a single
- command that does exactly what you need, but you can usually get
- virtually ANY job done by combining two or more commands and placing them
- in a subroutine. Once the subroutine is written, it becomes basically as
- easy to use as a built-in script command is.
-
- 3.2 Writing a Subroutine
-
- Writing a subroutine is no different than writing any other portion of
- your script, with two exceptions: you must think up a 'name' for a
- subroutine, and you must use a RETURN command to exit the subroutine
- (back from where it was called). Example:
-
- MySubroutine:
- print "I am now in 'MySubroutine'"
- return
-
- The above subroutine is called 'MySubroutine' and it could be executed
- from anywhere in a script using the command:
-
- GOSUB MySubroutine ;note that the colon is not specified
-
- Subroutines can be placed anywhere in your script, though the most common
- place to put new subroutines is right at the end of the script. The
- reason they will normally be placed at the 'end' is so you can easily
- avoid running into them by placing an EXIT (or RETURN) command just above
- the beginning of all your subroutines. Example:
-
- GOSUB InitScript ;Initialize (define and set up any variables)
- ... ;main body of script here
- EXIT ;EXIT (or RETURN) after the main body
-
- ;Now you can't run into 'InitScript' accidentally
-
- InitScript:
- ...
- RETURN ;and you can't run into 'Subroutine2' accidentally
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 30
-
-
-
- Subroutine2: ;and so forth...
- ...
- RETURN
-
- Subroutine3:
- ...
- RETURN
-
- Remember that the script processor simply ignores 'Labels:' if if happens
- to run into them in the normal course of running a script. Without the
- EXIT and RETURNs above, all the subroutines would be executed when the
- main body of the script ran into the subroutine labels below it.
-
- 3.3 GOSUB In Detail
-
- When the script processor runs across a GOSUB command, it first saves its
- current position (the 'current' position will be the END of the line on
- which the GOSUB was found), then searches from the top of the script for
- the 'Label' you specify AFTER the GOSUB command. If the label is found,
- execution of the script then begins on the next script line after the
- label (labels, which are always followed by a colon, are always ignored).
- The next time a RETURN is found (whether it was actually in the
- subroutine or not; you can GOTO out of one subroutine and execute
- another, then RETURN from there) the position saved when the GOSUB found
- is then 'popped' off the GOSUB stack, and script execution returns to the
- next command after the *last* GOSUB (if any).
-
- The GOSUB 'stack' (the place where the script processor saves the
- position of GOSUB commands, before executing the subroutine) can hold 16
- positions. Thus, you can execute up to 16 'nested' GOSUB commands (GOSUB
- from *within* a subroutine) before executing a single RETURN. If you
- attempt to execute 17 GOSUBs before using a RETURN, you earn a "GOSUB
- Stack Overflow" error, and your script aborts.
-
- As RETURN commands are encountered, the script processor returns to the
- position of the *last* GOSUB command. Example (see the comments [;] for
- an explantion):
-
- GOSUB Subroutine1
- exit
-
- Subroutine1:
- print "Executing subroutine 1."
- GOSUB Subroutine2
- RETURN ;would return to the EXIT below 'GOSUB Subroutine1' above
-
- Subroutine2:
- print "Executing subroutine 2."
- RETURN ;would return to the RETURN below 'GOSUB Subroutine2' above
-
- And again, it makes no difference whether the RETURN commands are
- actually 'in' the subroutine. If 'GOTO Subroutine2' was used above,
- instead of GOSUB, the RETURN found in Subroutine2 would cause a return to
- the EXIT command below the call to Subroutine1. Just picture the
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 31
-
-
-
- positions of your GOSUB commands being placed in a hat one after the
- other (you can't get to the previous position without removing the last
- one) with the RETURN command simply removing those positions (last in,
- first out) and you'll have no surprises.
-
- Note also that there is no difference between a GOTO label, and a GOSUB
- label. You can GOTO a subroutine label if you like -- but be cautioned
- that if a RETURN is found -- and no GOSUB was executed previously (i.e.
- there are no saved positions on the subroutine stack), it causes the
- script to end.
-
- 3.4 Creating a Subroutine Template
-
- If you find yourself writing the same subroutines over and over again in
- your scripts, you should consider creating one or more subroutine
- "template" files, which contain your common subroutines. You can call
- template files anything you like: TEMPLATE.SCR is a good choice. Then,
- whenever you begin writing a new script, simply hilight TEMPLATE.SCR,
- select "Copy" from the Script Manager, and copy it to another filename
- (the name of the script you wish to create). Then begin your script by
- "Edit"ing the newly copied template.
-
- All the subroutines will be in place, and you can begin coding
- immediately. This practice will also help you to standardize the names
- of your subroutines, so that you're always using the same subroutine
- label for a specific function (PressAKey, instead of Press_a_Key,
- PressKey, etc., which could get confusing after a time). It will also
- give you more reliable scripts, since you'll be using (hopefully) tested
- subroutines instead of writing from scratch, where you might make a
- mistake.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 32
-
-
-
- 4. SCRIPT VARIABLES IN DETAIL
-
-
- 4.1 Why Would I Want to Use Variables?
-
- Variables are what allow computer programs (and scripts) to "know"
- something. They give your scripts a memory so that they can remember
- things, and thus become smarter. If an error occurs, you can have the
- script remember the error or count the occurrences of errors through the
- use of variables. If you need the user to enter something (a phone
- number or the like), you can have your script store what the user enters
- in a variable, and thus your script can 'remember' what the user entered.
- Without variables, scripts have no way of remembering anything at all.
-
- Variables are also REQUIRED by several of the script commands. If you
- want to do any math (add, subtract, multiply, divide numbers) get
- keyboard input from the user, read text files on-disk, or do any sort of
- string 'handling' (joining two pieces of text together, extracting
- characters from a line of text, reading text from the video screen, etc.)
- then you must use variables to store the results.
-
- There are six types of variables in the Icom script language: 'User-
- Defined Variables', which you create yourself in your scripts, 'Global
- Variables' which are similar to the User-Defined Variables but exist for
- the duration of the Icom session, 'System Variables', which are similar
- to the Global Variables, but hold information about your computer system
- and Intellicomm, BIF Variables, which hold all the current BIF
- information, Main Setup Variables, which hold all the current INI
- (INItialization or main setup) information, and Permanent Variables,
- which are stored on-disk.
-
- Each type has a different purpose but the reason for variables of all
- types is to hold information and thus to avoid specifying CONSTANT data
- in your script commands. Anywhere you can specify constant data in a
- script parameter ('PRINT "John Smith"' prints constant data), you can use
- a variable ('PRINT myvariable' prints the CONTENTS of the variable
- 'myvariable'). Several examples are given below to show you how to make
- effective use of all types of variables.
-
- 4.2 Where you CAN'T use Variables
-
- You cannot use variables in place of script GOTO/GOSUB labels. If you
- try, you'll get a 'Label not found' error, or worse, Icom will jump to a
- 'label:' you didn't expect it to jump to. 'GOTO myvariable' (if
- myvariable was a variable) would cause Icom to look for a LABEL called
- 'myvariable:'. Thus, you cannot use variable names when a GOTO/GOSUB
- label is expected.
-
- 4.3 User-Defined Variables
-
- User-defined variables are variables you create yourself. All you do to
- create a variable is think up a name for it, then use the VARIABLE
- command to define it in your script:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 33
-
-
-
- VARIABLE myvariable ;define a variable called 'myvariable'
-
- You can also 'assign' something to the variable when you define it by
- following the variable name with whatever you want to assign to it:
-
- VARIABLE myvariable "Please hold this text in myvariable"
-
- Once the variable is defined, you can use it in any script command that
- accepts parameters. If you printed this variable above:
-
- PRINT myvariable
-
- ...then PRINT would display this on the screen:
-
- Please hold this text in myvariable
-
- If you intend to upload your script to a BBS for public distribution,
- User-Defined Variables also make it easier for users of your script to
- fill in any required information. Instead of forcing the user to weed
- through the entire script and make prompt or response changes, you can
- define all the necessary information using variables at the TOP of the
- script where they can easily be found:
-
- VARIABLE YourName "John Smith" ;<-- Put your name here
- VARIABLE Password "password" ;<-- Put your password here
-
- Placing variables at the TOP of the script makes it much easier for a
- novice to edit, and it also makes it easier for YOU to maintain your own
- scripts than it would be to have to weed through the script and change
- WHEN or SEND commands.
-
- 4.4 User-Defined Variable Rules
-
- User-Defined Variables cannot be used in script commands until you define
- the variable (give it a name) using the VARIABLE command. And you must
- define each variable with the VARIABLE command ONCE and only once (per
- script ... you can use the same variable name in another script). After
- you've defined it, you can change the contents of the variable using
- ASSIGN and several other commands, but the VARIABLE command should be
- used only once per variable. If you do this:
-
- variable x 0 ;define variable 'x', store 0 in it
- variable x 10 ;define variable 'x', store 10 in it
-
- Icom will abort the script with a 'Variable exists' error when it finds
- the second VARIABLE command. What you would do instead of using the
- variable command twice is this:
-
- variable x 0 ;define variable x, store 0 in it
- ...
- assign x 10 ;later in the script if you want to change the
- ; value, you use ASSIGN. This example would store the
- ; number 10 in variable x.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 34
-
-
-
- ASSIGN can be used to assign either text or numers to a variable.
-
- You cannot use a script COMMAND as a variable name:
-
- variable waitfor ;duplicates the WAITFOR command
-
- If you do this inadvertently, the script will abort with the error:
- 'variable name duplicates a script COMMAND'. At that point you simply
- think up a new name (add a 1 to the end of the variable name VARIABLE
- WAITFOR1 or the like) and you're set.
-
- Case is NOT significant in variable names:
-
- variable myvariable ;lowercase
-
- assign MYVARIABLE 10 ;uppercase... they're both the same to Icom
-
- You can store anything in a variable; numbers, text, symbols, graphics
- characters ... anything you like (including control characters).
- However, the maximum length for data stored in each user-defined variable
- is 256 characters.
-
- User-defined variable names can also be (almost) any name you like. If
- you were counting something you might use this:
-
- variable count 0 ;define variable 'count', assign 0 to it
-
- If you were storing your name, you might use this:
-
- variable MyName "John Smith"
-
- You CANNOT do this, however:
-
- variable My Name "John Smith" ;note the space in 'My Name'
-
- Spaces aren't allowed in variable names. You can use only letters,
- numbers (see below), and underscores (_):
-
- variable My_Name 10 "John Smith" ;this is fine with an underscore
-
- Further, you cannot BEGIN a variable name with a number: it must start
- with a non-numeric character. You can use numbers after the first
- character, but the very first character of a variable name must be either
- a letter or an underscore. These are all valid variable names:
-
- VARIABLE count1 ;numbers are okay after the 1st character
- VARIABLE c1
- VARIABLE _1
-
- but you cannot use this:
-
- VARIABLE 1count ;cannot start a variable name with a number
-
- Icom stores only the first *30* characters of variable names you define
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 35
-
-
-
- with the VARIABLE command in its internal table of variable names, and
- again only checks the first 30 characters when you specify a variable in
- a script command parameter. These two variable names are the exact same
- names to Intellicomm:
-
- VARIABLE this_is_very_long_variable_name_1
- VARIABLE this_is_very_long_variable_name_2
-
- The cutoff point, 30 characters, leaves Icom with:
-
- VARIABLE this_is_very_long_variable_nam
-
- for BOTH of the above variable names. The above would abort the script
- with a 'Variable exists' error, since you can't define the same variable
- twice in the same script.
-
- 4.5 Why All the Rules?
-
- The 30 character limit to variable names is common in programming and
- script languages (some allow more, many allow less) and the main reason
- is to conserve memory. Every name of every variable you create has to be
- stored in memory in an internal table, so the script processor can find
- the data when you specify the variable name in a script command. 30
- characters is a reasonable trade-off between memory conservation and
- functionality.
-
- Intellicomm also has to have some way of knowing whether you're
- specifying a constant number (1 for example is a constant number), or
- constant text (surrounded by single or double quotes), or a variable.
- The rules outlined above are how it does it. If a parameter starts with
- a single or double quote, the script processor knows you're specifying
- constant text. If a parameter starts with a number it assumes you're
- specifying a constant number. If a parameter has neither a quote nor 0-9
- as the first character, the script processor assumes you're specifying a
- variable name and will check its internal tables of variable names to
- locate the proper data. Most computer languages use these same rules to
- separate constants from variables, and numbers from text (strings).
-
- Further, other symbols such as +, -, =, <, >, /, *, %, ^, &, |, $, !, [],
- (), etc., may all be used for various purposes in future expansions of
- Icom's script language (or are already used), so for maximum
- compatibility with future releases you can use only a-z, A-Z, _, and 0-9
- (subject to the rule above about numbers) in your variable names. By
- VARIABLE NAMES this doesn't mean the text you specify between the quotes
- that is assigned to variables. Between quotes you can use any characters
- you like (almost... you can't use a real Line Feed or it would put the
- text on another line... use "^J" [Ctrl-J] for LF).
-
- Variable names themselves must never be put in quotes, or Icom will think
- you're specifying literal text and won't check its table of variable
- names. If you did this:
-
- PRINT "myvariable"
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 36
-
-
-
- the text "myvariable" (minus the quotes) would simply be printed to the
- screen. To print the contents of a variable called myvariable, do not
- use quotes:
-
- PRINT myvariable ;this accesses the CONTENTS of variable 'myvariable'
-
- 4.6 Using Variables
-
- You can use variables in any of Intellicomm's script commands that accept
- parameters, instead of specifying the parameters literally. You wouldn't
- want to have to write five different scripts that all do the same thing,
- but simply account for slightly different conditions such as a different
- phone number; so instead of changing one script line then duplicating the
- entire script, you just use variables, then change the variables, and the
- script works as is.
-
- This command could dial only "Joe's BBS":
-
- dial "Joe's BBS"
-
- While this script, using variables, could dial any BBS:
-
- variable BBSName ;define variable 'BBSName'
-
- boxgets BBSName 20 "Dialing a BBS" "Enter the name of a BBS to dial"
- dial BBSName
-
- We used a new command here that you haven't seen before, called BOXGETS
- and what it would do (given the parameters above) is accept a 20
- character string (the 20 following command) in a box that looked like
- this, but with graphics characters instead of text:
-
- +=| Dialing a BBS |==================+
- | |
- | Enter the name of a BBS to dial |
- | |
- | > |
- | |
- +====================================+
-
- Whatever was entered in the box would be stored in the variable 'BBSName'
- (the first parameter in the BOXGETS command). You then just
-
- DIAL BBSName
-
- and whatever name was entered in the box would be dialed.
-
- When you check the detailed command summary for BOXGETS you'll find all
- the details, such as how to check to see whether the user pressed the
- [Esc] key, how to look for a blank string, etc. You should also look up
- the DIAL command, since it can be used to simply display the entire BBS
- Directory, allowing the user to Tag/Dial BBS's... which may be more
- desirable than what was done above.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 37
-
-
-
- When you apply the same concept we used with the DIAL command above to
- WHEN, WAITFOR, and all the other script commands, using variables instead
- of specifying text directly, it allows you to write much more flexible
- scripts (and you may see more clearly how Icom itself works... it simply
- loads the BIF information into its variables and executes the same code
- no matter what BBS is being called).
-
- You needn't get variable information from the keyboard; you can get it
- from a BIF, the Icom main setup data, from a text file on-disk which you
- can create yourself manually or with other script commands, or you can
- create variable data on-the-fly based on day of week ($DOW), month
- ($MONTH), day of month ($DAY), time ($HOUR, $MIN, $SEC), etc. For
- example:
-
- variable BBS_to_call
-
- if $DOW = 1 assign BBS_to_call "Joe's BBS"
- if $DOW = 2 assign BBS_to_call "Canada Remote System"
- if $DOW = 3 assign BBS_to_call "Sound Advice"
- ; ...etc.
- DIAL BBS_to_call
-
- The first IF statemtent means 'if the day-of-week is equal to Sunday (1),
- put the text Joe's BBS in variable BBS_to_call'. If $DOW is equal to 2
- (Monday), we ASSIGN another BBS name. I.e. we are ASSIGNing data to the
- variable on-the-fly, according to the day of the week.
-
- You don't have to use variables for the time being, and are actually
- better off sticking with literal text and numbers until you get the hang
- of things. In the beginning the main goal is to write scripts that WORK.
- Writing flexible scripts with variables is something you can look into
- when you're comfortable with the language and have written a few working
- scripts without variables. A good way to get practice is to write your
- scripts with constants first, get them working, and THEN to go and
- replace one or two of the constants with variables to get the hang of it.
-
- 4.7 The Life of a Variable
-
- User-Defined Variables have a fleeting life most days. They live (exist
- in memory) only from the time they are defined with the VARIABLE
- commmand, and they die (do not exist in memory) when the script ends.
- Their use is also limited to the current script. If you created one
- script that did this:
-
- variable I_Need_This_Number_Elsewhere 10
-
- ...then created another script and executed that second script using the
- SCRIPT command and tried this in the SECOND script:
-
- print I_Need_This_Number_Elsewhere
-
- then Icom would abort the second script with the error: "Undefined
- Variable; I_Need_This_Number_Elsewhere". Variables defined with the
- VARIABLE command are accessable only from the script in which they were
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 38
-
-
-
- created, and only from the point of creation onwards. You can't do this
- either:
-
- print x ;don't attempt to use here
- variable x 10 ; when it hasn't been defined yet
-
- Before using a variable the FIRST thing you must do is define it with the
- VARIABLE command. Otherwise Icom won't have the name of the variable in
- its internal table of variable names, and also won't have allocated any
- memory space to store the variable data. Variables can be used 'above'
- the VARIABLE command if you can manage to get the variable defined first.
- You can do this for example:
-
- gosub define_variables ;jumps to 'define_variables:', then returns
- print x ; <-- to this line when the subroutine 'returns'
- exit ;exit before we hit 'define_variables' again
-
- define_variables: ;beginning of subroutine 'define_variables'
- variable x 10 ;define variable 'x' for use above
- return ;end of subroutine 'define_variables'
-
- Having variables disappear when a script ends, and only allowing the
- current script to access them may seem like a limitation at first, but
- both are actually useful features, and both were done intentionally. If
- variables DID exist after the script ended, you'd be tieing up memory on
- the computer, possibly never to be used again during that Icom session.
- By having variables 'die' when the script ends, all the memory they were
- using is freed up.
-
- The other feature; limiting the use of variables to the current script is
- also very useful. If you had one script that used a variable called 'x',
- and you had some important data in 'x' and then called ANOTHER script
- (using the SCRIPT command, which runs a script from a script) that used
- the same variable name... you may lose your original value in 'x' if the
- second script also had an 'x' and modified the value. If variables
- didn't work this way you'd constantly have to worry about conflicting
- variable names in other scripts, that might change your original data...
- and tracking down such problems would not be easy.
-
- 4.8 Global Variables
-
- For the cases where you DO want certain data to be available from one
- script to another (for inter-script communication and the like) an
- 'array' of 'global variables' has been provided. Did your face go pale?
- I know it sounds rather complicated, but the Global Variables can be very
- useful and are well worth knowing about.
-
- The 'global' script variables are available from the second Icom starts
- until you exit the program. I.e. they hold their data from one job to
- the next, from one script to the next (with some exceptions... see below)
- -- for as long as Icom itself remains in memory. The global variable
- array is called GlobalStr (Str for 'String'... that means it can hold
- text OR numbers, as with the User-Defined Variables).
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 39
-
-
-
- The term 'array' just means that there are more than one of them: there
- are 10 in fact. The first is GlobalStr[0], the second is GlobalStr[1],
- the third is GlobalStr[2], etc., all the way up to GlobalStr[9] (0-9 = 10
- variables). The GlobalStr variables are each 64 characters long, so you
- can't store anything longer than 64 characters in any one of the 10
- GlobalStr array members. If you attempt to store something longer than
- 64 characters, the data will be truncated (cut) at 64 characters by the
- script processor.
-
- Now you're probably wondering about those square brackets, and may be
- wondering why it's not just GlobalStr1, GlobalStr2, etc. The reason for
- that, and the reason for arrays in general in all programming languages,
- is so that you can use ANOTHER variable to specify WHICH of the global
- variables you want to access. Watch this carefully:
-
- variable Name_Data 5 ;define Name_Data, assign 5 to it
-
- printnc "Enter your name: " ;print with no carriage return
- gets GlobalStr[Name_Data] 64 ;get user name, store in GlobalStr[5]
- print GlobalStr[Name_Data] ;print GlobalStr[5]
-
- (The 64 following the GETS command specifys the maximum number of
- characters to get. Remember; each GlobalStr member can hold a maximum of
- 64 characters.)
-
- Instead of specifying a constant number in the square brackets of
- GlobalStr, we used the variable 'Name_Data', which was holding the value
- of 5. So, GlobalStr[5] gets the data, since 5 is what 'Name_Data' was
- holding. Later in your script you might not remember that you stored the
- user's name in GlobalStr[5], so it's much easier to just assign the value
- of 5 to 'Name_Data', and then to use GlobalStr[Name_Data]. It's easier
- to work with and remember than GlobalStr5 would be, were it not an array.
-
- One thing you CANNOT do, at least in this version of the Icom script
- language is this:
-
- GETS GlobalStr[GlobalStr[5]] 64
-
- In real programming languages this sort of thing IS legal... and all it
- would do is access the contents of GlobalStr[5] to get the array offset.
- If GlobalStr[5] was holding the value 1, a real programming language
- would store the result of the GETS command above in GlobalStr[1].
- However once we get into things like that, this becomes possible:
-
- GlobalStr[GlobalStr[GlobalStr[GlobalStr[2]]]]
-
- ...and that's a little too involved to program the script interpreter to
- handle at present. I may get into it in the future, but didn't have time
- for v2, so you MUST use either a constant number:
-
- GlobalStr[0] to GlobalStr[9]
-
- Or a user-defined variable (defined with the VARIABLE command) that is
- HOLDING a number from 0-9:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 40
-
-
-
- variable globalstr_offset 9 ;assign 9 to globalstr_offset
-
- GlobalStr[globalstr_offset] ;GlobalStr[9]
-
- You MUST NOT USE SPACES anywhere from GlobalStr[ to the closing ]. These
- are programming errors:
-
- GlobalStr [offset] ;space between GlobalStr and [
- GlobalStr[ offset ] ;spaces in the brackets
- GlobalStr[ 5 ] ;spaces in the brackets
-
- It must be kept together as a single unit, with no spaces, and this is
- the correct way to specify the three example errors above:
-
- GlobalStr[offset]
- GlobalStr[offset]
- GlobalStr[5]
-
- 4.9 Using Global Variables
-
- Until you become more familiar with the other script commands and
- concepts it's difficult to demonstrate any advanced use of these
- variables. But their purpose is threefold: (1) to allow inter-script
- communication (access to the same data by multiple scripts... which isn't
- possible with the User-Defined Variables), (2) to allow 'command line
- parameters' to be passed to scripts from DOS (the /scr: command line
- switch) BIFs, Custom Commands, and other scripts (the parameters are
- stored in the GlobalStr array), and (3) basic array usage, which, in real
- programming languages is indespensible.
-
- The main idea behind an array is to use ANOTHER variable as an index to
- access members of the array. You can start the index variable
- ('Name_Data' in the example above was the index variable) at 0, then add
- one to the index variable whenever you need another global variable:
-
- variable gindex 0 ;start at 0
-
- assign GlobalStr[gindex] "Some data" ;goes in GlobalStr[0]
- inc gindex ;INCrement: gindex = gindex + 1
-
- ; ... later in your script
-
- assign GlobalStr[gindex] "More data" ;goes in GlobalStr[1]
- inc gindex ;gindex now equals 2... ready
- ; for the NEXT bit of data
-
- Or you can use a 'loop' to clear all the variables in the array, or
- combined with other functions can quickly copy data from various sources
- into the array. A 'loop' simply means that Icom will execute the
- commands between WHILE and ENDWHILE (below) as long as the condition
- specified in the WHILE remains true. I.e. as long as the value in
- 'offset' is less than or equal to the number 9 (9 being the GlobalStr
- array limit... GlobalStr[9] is the end of the array). Since we start
- with 'offset' at 0, and add one to it at the bottom of the loop, the
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 41
-
-
-
- commands in the loop will be executed 10 times each. More details on
- loops can be found in the WHILE Detailed Command Summary. Here's a quick
- example:
-
- variable offset 0 ;define variable 'offset', set to 0
-
- while offset <= 9 ;while offset is less than or equal to 9
- printnc "Enter item " ;These five lines in the loop will be
- printnc offset ; executed UNTIL 'offset' is greater than
- printnc ": " ; 9. When 'offset' is 10, we exit the
- gets GlobalStr[offset] 40 ; loop and continue below ENDWHILE
- inc offset ;increment: offset = offset + 1
- endwhile ;end of the 'loop'
-
- print "Here is what you entered:"
- assign offset 0 ;It's very important to reset 'offset' to 0
- while offset <= 9 ; or else we wouldn't enter this 'loop' at
- print GlobalStr[offset] ; all. Remember it's now holding the number
- inc offset ; *10* due to the loop above, and 10 is NOT
- endwhile ; less than or equal to nine.
-
- Loops and arrays were invented to avoid having to do this:
-
- printnc "Enter item 0: "
- gets GlobalStr[0] 40
- printnc "Enter item 1: "
- gets GlobalStr[1] 40
- printnc "Enter item 2: "
- gets GlobalStr[2] 40
- ;this would continue right up to GlobalStr[9] to accomplish
- ; the same thing the FIRST loop above did.
-
- print "Here is what you entered:"
- print GlobalStr[0]
- print GlobalStr[1]
- print GlobalStr[2]
- ;this would also continue right up to GlobalStr[9] to accomplish
- ; what the SECOND loop above did.
-
- Of course, the same principle can be applied to ANY script command (any
- commmand that takes a parameter), and GlobalStr isn't limited to GETS and
- PRINT and ASSIGN. You can use this global array variable anywhere your
- imagination takes you, with any script command that takes parameters.
-
- 4.10 Passing Parameters to Scripts
-
- When parameters are passed to a script, either from the BIF:
-
- | Your Logon Name> @DEMO parm1 parm2 Name . . . . . . st Name? Æ |
- ^^^^^^^^^^^^^^^^^
- or from a Custom Command:
-
- | 12 Custom Command/Run script | CC: @DEMO parm1 parm2 ... |
- ^^^^^^^^^^^^^^^^^
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 42
-
-
-
- or from a script via the SCRIPT command:
-
- SCRIPT "DEMO.SCR" "parm1" "parm2" variable_parm
-
- or from the ICOM.EXE /scr: command line option:
-
- ICOM.EXE /scr:"DEMO.SCR parm1 parm2"
-
- the first parameter is stored in GlobalStr[1], the second in
- GlobalStr[2], then GlobalStr[3], and so on. The quotes are needed when
- specifying parameters in the /scr: command line option (see above) to
- keep it all together. Otherwise DOS separates the parameters due to the
- spaces between parameters, and they look like separate 'switches' to
- Icom.
-
- Note that when using the SCRIPT command, you can pass VARIABLES instead
- of literal strings (variable_parm above assumes the script had a variable
- called variable_parm), which simply has the effect of copying the
- variable data into the GlobalStr array. As mentioned previously the
- regular user-defined variables are available ONLY within the script
- they're defined in. By using variables as parameters in a SCRIPT
- command, the called script could then access the data by looking in
- GlobalStr. You can also just copy the data explicitly, if you like,
- instead of passing parameters:
-
- assign GlobalStr[1] "parm 1" ;copy 'parm 1' into GlobalStr[1]
- assign GlobalStr[2] "parm 2"
- assign GlobalStr[3] variable_parm
- SCRIPT "DEMO.SCR"
-
- The above has the same effect as the previous example, which specified
- parameters directly in the SCRIPT command.
-
- NOTE: When passing parameters from a BIF or Custom Command, Icom
- separates the parameters by looking for space " " characters. As soon as
- a space is found, the data following the space goes in the next GlobalStr
- member. If you wish to pass a single parameter which CONTAINS a space,
- you must put the parameter in quotes (similar to DOS command line
- options):
-
- | 12 Custom Command/Run script | CC: @DEMO "parm 1" "parm 2" |
- ^^^^^^^^^^^^^^^^^^^^^^^
- The two parameters specified above would go in GlobalStr[1] and
- GlobalStr[2] (the quotes are stripped before storing the parameter(s) in
- GlobalStr).
-
- Alternatively you could just put quotes around ALL the parameters (to
- have them all stored in GlobalStr[1]), then use the STRITEM command to
- get the individual parameters yourself:
-
- | 12 Custom Command/Run script | CC: @DEMO "parm1 parm2" |
- ^^^^^^^^^^^^^^^^^^^
- From inside the script you'd do this to get the individual parameters:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 43
-
-
-
- variable parm1
- variable parm2
-
- ;GlobalStr[1] would be holding "parm1 parm2" (no quotes) given the
- ; Custom Command example above
-
- STRITEM parm1 GlobalStr[1] 1 ;get item 1 from GlobalStr[1], put in parm1
- STRITEM parm2 GlobalStr[1] 2 ;get item 2 from GlobalStr[1], put in parm2
-
- Please see the Detailed Command Summary for more information on STRITEM.
-
- 4.11 Checking the Number of Passed Parameters
-
- If you were paying close attention earlier, you might be wondering why
- the parameters don't start at GlobalStr[0] ... since GlobalStr[0] is the
- FIRST variable in the array ... not GlobalStr[1]. The reason for that is
- to allow you to quickly check how many (if any) parameters were passed to
- your script. The script processor stores the total number of parameters
- (a number from 0 to 9) passed to your script in GlobalStr[0]. So, if
- your script REQUIRED 3 parameters to be passed to it, and they weren't
- all specified, you'd know about it quickly:
-
- if GlobalStr[0] <> 3 ;if GlobalStr[0] is not equal to 3
- msgwind "Hey, you were supposed to specify 3 parameters!"
- return
- endif
-
- print "Thanks for the 3 parameters. You specified:"
- print GlobalStr[1]
- print GlobalStr[2]
- print GlobalStr[3]
- return
-
- It's as easy as 0-1-2 (or 1-2-3, whichever you prefer). Of course, this
- GlobalStr[0] business is something you'll have to keep in mind (a) if
- you're storing anything important in GlobalStr[0] and (b) if you use the
- SCRIPT command to call another script from your existing script. I.e. if
- anything important is stored in GlobalStr[0] (your own data... Icom
- doesn't care what's in GlobalStr[0]) you'll lose it if you execute a
- SCRIPT command from within the current script. You can overcome any
- problems by doing this:
-
- variable some_variable
-
- assign GlobalStr[0] "Important data" ;holding something important
- ... ;meanwhile, later in the script...
- assign some_variable GlobalStr[0] ;save GlobalStr[0]
- script "ANOTHER.SCR" ;run ANOTHER.SCR
- assign GlobalStr[0] some_variable ;restore GlobalStr[0]
-
- Note that even though you didn't PASS any parameters to ANOTHER.SCR, the
- script processor would still store the number 0 in GlobalStr[0], to tell
- ANOTHER.SCR that no parameters were passed. Of course, if you DID pass
- parameters to ANOTHER.SCR, then GlobalStr[1] and possibly GlobalStr[2],
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 44
-
-
-
- etc., would also be lost, depending on how many parameters you specified.
- If you pass 9 parameters to a script then the entire GlobalStr array is
- overwritten with your parameters.
-
- Now that you know this though, it should be no problem to simply save any
- important data in GlobalStr before executing the SCRIPT command, then to
- restore the information after the SCRIPT command as illustrated above.
-
- TIP: If you DO have something important to hang onto (and it must be
- 'globally' available to other scripts), you're much better off storing it
- in GlobalStr[9] than you are storing it in GlobalStr[0]. It's not likely
- that 9 parameters would ever be passed to a script, so keep your
- important global data at the high end of GlobalStr, and keep the lower
- portion open for passing parameters. Data stored in GlobalStr[9],
- GlobalStr[8] probably all the way down to GlobalStr[5] would most likely
- remain untouched throughout the entire Intellicomm session, from one job
- to the next, from one script to the next, etc.
-
- If the data won't be needed outside the current script though, there's no
- need to use GlobalStr at all... you can just use the regular variables
- (defined with the VARIABLE command), which are protected when you run
- another script.
-
- 4.12 System Variables
-
- You can also obtain various system information to use with script
- commands and to put in your variables, such as the system date and time,
- the current up/download directories and protocols, and lots of other
- useful information. System variables begin with a dollar sign ($) and
- can be used in any Icom script command that accepts parameters:
-
- print $DATE
-
- This command prints today's date to the screen (in the date format
- defined by the user in the Icom main setup... usually MM/DD/YY). System
- Variables increase flexibility and allow you to write scripts for use by
- others, since you needn't use constant data. For example, DOWNLOAD "Z"
- was used to demonstrate the download command earlier, but that's
- inflexible and forces Zmodem. With Icom, everyone defines the upload and
- download protocols they prefer to use in their BIFs, so instead of using
- "Z", you can use a System Variable:
-
- download $DL_PROTOCOL
-
- Whatever protocol the user had defined as the file download protocol (in
- whatever BIF was currently loaded) would then be called to carry out the
- download -- even if it was an external protocol. You can also use System
- Variables to *check* settings if need be:
-
- if $DL_PROTOCOL <> "Z" ;not Zmodem?
- print "Sorry, this script requires use of Zmodem. Please set your"
- pause "BIF up to use Zmodem and re-try. Press a key..."
- exit
- endif
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 45
-
-
-
- You could also just ASSIGN $DL_PROTOCOL "Z" to have your script change
- it, instead of aborting the script... but if you do that, make sure you
- save the ORIGINAL value of $DL_PROTOCOL in a user-defined variable, and
- restore the value before your script ends.
-
- Please see the System Variable Appendix and/or the SCRIPT COMMANDS AT A
- GLANCE section of SCRIPT.DOC for a listing of all the System Variables.
-
- 4.13 BIF Variables
-
- BIF Variables start with an asterisk (*), are then followed by the BIF
- 'section' in square brackets ([G] = General screen, [L] = Logon screen,
- etc) then the "tag" of the BIF item. Example:
-
- WHEN *[L]namp SEND *[L]namc ;BIF Logon name prompt/command (response)
-
- You can access (and change, if necessary) any of the BIF variables in
- this way. All the BIF sections and tags are documented in SCRIPT.DOC in
- the "BIF Variables" section.
-
- NOTE: Until Icom dials or connects to a BBS, and after it disconnects,
- the BIF data is unpredictable and could be that of any BBS (check the
- $BIF_NAME System Variable to get the filename of the currently loaded
- BIF, if any). You can use the LOADBIF command to load a specific BIF
- into memory if you need specific BIF data.
-
- 4.14 Main Setup and Environment Variables
-
- You can also access (and change) any of the Icom main setup by specifying
- an asterisk (*) followed by a main setup "tag". Example:
-
- ASSIGN *dtime 60 ;60 second 'Timeout' when dialing
-
- Each variable holds a specific piece of information, in a specific FORMAT
- and you shouldn't use any of these variables before reading the "Main
- Setup Variables" section in SCRIPT.DOC.
-
- Note that these settings are stored on-disk in ICOM.INI by default, which
- is loaded into memory (the Main Setup Variables) when Icom initializes.
- If necessary you load and save various .INI files using the LOADINI and
- SAVEINI commands.
-
- 4.15 Environment Variables
-
- You can also access variables in the ICOM.EXE program 'environment'
- (where the DOS PATH is stored, and any other environment variables the
- user had defined with the DOS 'SET' command) using GETENV / SETENV. Each
- of these commands is described in the Detailed Command Summary section of
- SCRIPT.DOC.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 46
-
-
-
- 5. PERMANENT VARIABLES: INTRODUCTION TO FILE INPUT/OUTPUT
-
-
- Permanent variables exist even after the computer is turned off. They're
- not stored in memory as the variables discussed above are; they're stored
- on-disk. Through the use of the script file Input/Output (file I/O)
- commands you can have your scripts 'remember' things forever... or at
- least until disk failure. Likely candidates to become "permanent"
- variables are any user-configurable settings your script must remember
- from one run to the next.
-
- You don't have to know anything about disks, or how DOS works with files
- to use the file I/O commands. If you can PRINT data on your monitor with
- a script, then you're just a couple of steps away from doing the
- equivalent of PRINTing data to a file using the file I/O commands.
-
- If you're nervous about using the disk, and think you might screw your
- whole hard drive up accidentally, relax. Using the script file I/O
- commands is no less "dangerous" than starting up your word processor,
- typing a letter, and saving it on-disk using the proper filename
- ('proper' meaning that you don't inadvertently type the wrong filename
- frequently and overwrite imporant files by accident). If you can do that
- without worrying about losing important data on your disks, then you're
- fully qualified to use the script file I/O commands: All you need to know
- about files, as with your Text Editor, is the D:\PATH\FILENAME.EXT of the
- file. They do nothing you can't already do from your word processor or
- text editor (except to automate the task of creating and maintaining the
- files... and to allow you to do it from a script instead of having to
- start up the Text Editor and do it manually).
-
- DOS takes care of all the nitty grittys as far as disk use goes (the
- script file I/O commands simply pass intructions to DOS, after verifying
- them) and DOS knows what it's doing. It won't *let* you screw up and
- unintentionally overwrite other files on your disk, no matter how hard
- you try. To overwrite existing data on-disk, you must be quite specific
- about your intentions. You can't open one file, and inadvertently write
- to another ... no more than you can load a specific file into your Text
- Editor and inadvertently end up overwriting some other file on-disk by
- "typing too much". It just doesn't happen. If you add to a file (any
- file) DOS uses *free* disk space to save the new data, and it will never
- overwrite the data in another file to expand an existing file: That's
- what "Disk Full" messages are for... and you'll get a "Disk Full" error
- using the File I/O commands as well, if there's no *free* space on disk,
- and you attempt to add new data to a file.
-
- And luckily, no rocket science is required: (1) You first open the file
- you're interested in, by specifying its filename; and this is why it was
- said above that you cannot UNINTENTIONALLY overwrite files on your hard
- drive ... unless you're a klutz with filenames; (2) you then read or
- write to the file line by line, transferring the information from the
- file into your variables (to memory), or from variables/constants into
- the file; (3) then you close the file. It's simple! Here's a quick
- example:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 47
-
-
-
- variable f1 ;variable used as the file "handle". You'll
- ; note below that FOPEN, FPUTS, and FCLOSE
- ; all use this variable
-
- FOPEN f1 "TEST.DAT" "w" ;open TEST.DAT for "w"riting; overwrites any
- ; files on-disk of the same name
- FPUTS f1 "John Smith" ;write this text to the file, following each
- FPUTS f1 "123 Anystreet" ; fputs with a Carriage Return/Line Feed. To
- FPUTS f1 "Anytown, Ont." ; write WITHOUT adding a CR/LF, use fputsnc
- FCLOSE f1 ;close the file
-
- If you executed the above script, you'd end up with a text file on-disk
- called TEST.DAT (in the current directory, whatever that happened to be)
- that contained the following:
-
- John Smith
- 123 Anystreet
- Anytown, Ont.
-
- The only 'danger' involved (when opening a file for "w"riting, as we did
- above) is in specifying the proper filename... just as you make sure to
- specify the proper filename when you save a file on-disk from your word
- processor. And just as in your word processor, if you don't specify a
- drive and path (D:\PATH\) with the FILENAME.EXT, the file is created in
- the current directory. By ALWAYS specifying the full
- D:\PATH\FILENAME.EXT of the files you FOPEN, you'll never have to worry
- about inadvertently overwriting useful files. In many of the examples
- below, the D:\PATH\ is omitted for brevity, but in a real script you must
- ALWAYS either use a CHDIR command, or specify the full
- D:\PATH\FILENAME.EXT. Either of these are fine:
-
- CHDIR "C:\SOMEDIR"
- FOPEN f1 "SOMEFILE.EXT" "w"
-
- FOPEN f1 "C:\SOMEDIR\SOMEFILE.EXT" "w"
-
- The latter is the safest, since a CHDIR command will fail if the
- directory doesn't exist... and were that the case, the first FOPEN would
- simply create SOMEFILE.EXT in the current directory, *overwriting* any
- file of the same name that happened to exist in whatever directory you
- were in at the time. Once you FOPEN a file for "w"riting, you
- immediately destroy the contents of any file of the same name. So make
- sure you get the filename right when you FOPEN for "w"riting!
-
- 5.1 FOPEN 'Modes'
-
- You can FOPEN a file for reading (no writing... the file must exist),
- writing (no reading... the file will be created and will overwrite any
- file of the same name) or 'appending' (add to the end of an existing
- file, or create the file if it doesn't exist). And once you master file
- I/O, you can even open a file for reading AND writing, if the need arises
- (more on this later). The "w" above in the FOPEN command (after the
- filename) specifies writing only, this mode overwrites any file of the
- same name that exists in the current directory; "r" specifies reading
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 48
-
-
-
- only, and "a" specifies appending (create or add to).
-
- 5.2 The File Handle
-
- The variable 'f1' is specified in all of the file commands to identify
- WHICH file you want to operate on. Several files can be FOPENed at the
- same time -- usually for the purpose of reading data from one file and
- writing it to another -- and it would be tedious to have to specify the
- filename every time:
-
- FOPEN "test.dat" "w"
- FPUTS "test.dat" "John Smith"
- ...
- FCLOSE "test.dat"
-
- And it would be even more tedious were you operating on a file called
- "C:\MYDIR\SUBDIR1\SUBDIR2\SOMEFILE.TXT". So instead of forcing you to
- specify the filename every time you operate on an open file, FOPEN takes
- a variable and then lets you use that variable name from then on (until
- after you FCLOSE the file) to 'refer' to the filename you specified in
- the FOPEN command.
-
- The variable name you choose for the file handle is up to you, and 'f1'
- was just an example. You could call the file handle variable 'test_dat'
- (or any other legal variable name) if you wanted to.
-
- Since you can FOPEN several files at a time, whenever you FPUTS (write
- to), or FCLOSE a file, the script processor has to know *which* file you
- want to operate on. FOPEN stores a number called a file "handle" in the
- variable you specify before the filename, and by specifying that same
- variable in all the file commands later, the script processor always
- knows which open file you want to deal with. Simple!
-
- If you ran the example script above, you could then load the file
- TEST.DAT into your Text Editor and read it or modify it just like any
- other text file. Or, at some later point on some later day you could
- load the information and use it in a script:
-
- variable Name ;define some variables
- variable Address
- variable City
- variable f
-
- FOPEN f "test.dat" "r" ;open for "r"eading
- FGETS Name f ;read first line, store in 'Name'
- print Name ; this prints John Smith
- FGETS Address f ;read next line, store in 'Address'
- print Address ; this prints 123 Anystreet
- FGETS City f ;read next line, store in 'City'
- print City ; this prints Anytown, Ont.
- FCLOSE f
-
- FGETS reads data from a file, and stores it in a variable (or variables
- in this case; Name, Address, and City). Note that FGETS takes the file
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 49
-
-
-
- handle (the variable 'f' holds the file handle) as the SECOND parameter.
- As with all script commands, the variable you're ASSIGNING data to is
- always the first parameter specified. FPUTS takes the file number as the
- first parameter because it doesn't assign anything to the variable, and
- also to allow you to FPUTS more than one item:
-
- variable some_text "some text"
- FPUTS f "This is " some_text " to FPUTS"
-
- After looking at the prior example, you may be wondering how FGETS knows
- what to store in which variable... How it knows to put the name in
- 'Name', the address in 'Address' and so on. But the fact is it doesn't:
- we do. All FGETS does is to read the file line by line. The first call
- to FGETS reads the first line... the second reads the second line, the
- third reads the third line. WE know that the first line contains the
- Name, and the second line contains the Address, etc., since we created
- the data file earlier in the first example. So we knew enough to call
- the variables 'Name', 'Address' and 'City' since that's what's in the
- data file. You 'could' do this, though it wouldn't make much sense:
-
- FOPEN f "test.dat" "r" ;open for reading
- FGETS f City ;read first line, store in 'City'
- print City ; <-- this still prints John Smith
- FGETS f Name ;read next line, store in 'Name'
- print Name ; <-- this still prints 123 Anystreet
- FGETS f Address ;read next line, store in 'Address'
- print Address ; <-- this still prints Anytown, Ont.
- FCLOSE f
-
- This serves to prove that the names of variables are irrelevant to the
- script processor... You can call a variable anything you like, and you
- can give ANY variable to ANY script command as a parameter. Whatever
- name you give the variable (and the variables you choose to use as script
- parameters) will only be meaningful to you ... and possibly to other
- human-types. The script processor will store anything, anywhere, with no
- regard to whether the actual variable name used 'makes sense'.
-
- So how does FGETS 'remember' which line to get out of a file next?
-
- The file I/O functions keep track of the "current position(s)" of all
- open files (until FCLOSE is called) with what is known as the "file
- pointer". FGETS and FPUTS simply move this pointer whenever you read or
- write to the file.
-
- If you use FPUTS, the data is written to the file (at the 'current'
- pointer position) and the file pointer is then moved ahead by however
- many bytes were written (plus two bytes for the Carriage Return/Line Feed
- [CR/LF] FPUTS adds to the end of each line). The next time FPUTS is
- called, it simply writes at the position of the file pointer and then
- moves the pointer ahead again.
-
- The same happens with FGETS, and the file pointer is moved ahead by
- however many bytes were in the line you just read. The next time you
- call FGETS it reads from the position of the pointer, then moves the
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 50
-
-
-
- pointer again to get ready for the next FGETS.
-
- FGETS is designed to read a single line of a text file, and it knows the
- end of the line by the Line Feed written at the end of each line by
- FPUTS. As soon as FGETS finds a LF, it stops reading the file, and moves
- the pointer ahead by however many bytes it read, to get ready for the
- next FGETS. The carriage return and line feed at the end of each line in
- the file are stripped by FGETS before it stores the data in the variable,
- since you'll rarely (if ever) want them.
-
- If you open a file for "a"ppending (add to the end of the file), FOPEN
- automatically moves the file pointer to the end of the file after it's
- opened, so that the firs time you FPUTS to the file, the data goes
- *after* any data already in the file (however, Ctrl-Z characters at the
- end of the file, if any, are overwritten. FOPEN automatically checks for
- Ctrl-Z's and moves the file pointer back so that the first FPUTS will
- overwrite any existing Ctrl-Z's).
-
- You can also read from and write to a file character by character by
- using FPUTC and FGETC, which both move the file pointer ahead by one
- character (one byte) per read/write. And you can FPUTS without adding a
- CR/LF by using FPUTSNC (NC for 'N'o 'C'arriage return).
-
- If you're wondering whether FGETS and FPUTS keep *separate* file
- pointers, and keep track of where data will be both read from and written
- to next, the answer is no. Reading from, and writing to the SAME file,
- with a single FOPEN, is simply not something you'll need to do very
- often. You 'can' do it, and we'll be discussing this below, but in all
- the examples so far we have EITHER opened a file for "r"eading (which
- means that writing is prohibited and if you attempt to FPUTS to the file,
- the FPUTS is ignored) or "w"riting (which means that FGETS [reading] is
- prohibited and FGETS is ignored). To both read and write, you must open
- the file in a special way, and it's really not something you're likely to
- have to do. What you'll usually do is FCLOSE the file, then FOPEN it
- again in another 'mode' to switch from reading to writing. And FOPEN
- automatically moves the file pointer back to the beginning (or end, if
- opened in "a"ppend mode) of the file, so there's no need for separate
- read/write file pointers.
-
- NOTE 1: As mentioned earlier, unless you specify a path with the filename
- in FOPEN, the file is created (or searched for, if opened for reading) in
- the *current directory*. The DOS PATH does not apply when FOPEN is
- looking for a file to open. Thus, you should always specify full
- pathnames when using FOPEN. You can use the $HOME_DIR System Variable to
- create files in the Icom home directory (where ICOM.EXE is), if your
- script will be used by others. The various Icom system directories
- ALWAYS have a trailing slash (even if you change a System Variable in
- your script and forget to add the slash, one is automatically added), so
- you can simply append filenames to these directories. Examples:
-
- FOPEN f "c:\mydir\some.dat" "a" ;create or 'a'ppend to
- FOPEN f "a:\catalog.txt" "r" ;open for 'r'eading
-
- variable test_dat $HOME_DIR "test.dat"
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 51
-
-
-
- ;$HOME_DIR would contain C:\ICOM\ or the like. Note how we assigned
- ; multiple items to 'test_dat' with a single VARIABLE command. The
- ; end-result in variable 'test_dat' would be C:\ICOM\test.dat or the
- ; like.
-
- FOPEN f test_dat "w" ;fopen "C:\ICOM\test.dat" "w"
-
- ;you can also open 'devices' in the same manner:
-
- FOPEN f "PRN" "w" ;open device 'PRN' (printer) for writing
- FOPEN f $PRN "w" ;ditto, but use the device the user has
- ; defined in the Icom main setup
- FPUTS "This goes to the printer!"
- FCLOSE f ;you still have to FCLOSE
-
- However, do not attempt to open a COM port that Icom is using! [It's
- okay if Icom isn't using it, and the port goes to a printer though.] The
- file I/O functions are not very well suited to communications in any case
- (it would work though, if you tried it on a port that Icom wasn't already
- using), and you're much better off using the PORT command (open a new COM
- port), then using SEND and the other COM-related commands, which were
- designed for efficient port I/O.
-
- NOTE 2: There is a limit in the number of files you can open with FOPEN
- (before calling FCLOSE, that is. You can open as many files as you like
- if you FCLOSE each file when you're done with it). The script processor
- can accomodate up to ten open files at a time... The eleventh FOPEN with
- no FCLOSE (i.e. trying to open eleven files at the same time... !?) earns
- you an "FOPEN stack overflow" error which aborts your script. But since
- it's really DOS that is handling the file I/O, you 'can' run into a
- problem opening a file before ten files are open. You are also limited
- to the number of DOS file handles the USER has set up in the CONFIG.SYS
- "FILES=" statement. If you ever wondered what this statement was for...
- now you know. As soon as DOS runs out of file handles, it prevents ANY
- program, system-wide, from opening more files. FILES= determines the
- total number of files that may be open on the system at the same time;
- and the monitor, keyboard, and other devices use up some of these DOS
- file handles before you even begin to run a program. [Your script does
- not use up a file handle though, since Icom loads scripts into memory,
- then FCLOSEs the script file.]
-
- If you ran a program prior to your script (a multitasker, etc) which has
- opened all the files DOS is set up to handle (FILES=)... you won't be
- able to FOPEN any files in your scripts. FOPEN sets the $ERRORLEVEL
- System Variable to 2 if no file handles are available, and if that
- happens you can print a message to the user asking for an increase in the
- FILES= of the CONFIG.SYS file:
-
- fopen fh "TEST.DAT"
- IF $ERRORLEVEL = 2
- print "Unable to open file TEST.DAT due to a lack of file handles."
- pause "Please increase the FILES= statement in your CONFIG.SYS
- file...."
- ENDIF
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 52
-
-
-
- Various other problems can also occur when you FOPEN a file. The most
- common is an invalid drive, path or filename (file not found) and in this
- case, $ERRORLEVEL is set to 1 by FOPEN. If you attempt to open a "read
- only" file in write mode, FOPEN sets $ERRORLEVEL to 3 (and prevents any
- attempted writing to the file, since the file simply will not be opened
- and you won't have a valid file handle). Thus, it's always wise to check
- $ERRORLEVEL after an FOPEN to see whether the file was successfully
- opened or not:
-
- FOPEN "test.dat" "r"
- if $ERRORLEVEL <> 0 ;$ERRORLEVEL = 0 if successful, <> is NOT equal to
- msgwind "Can't find/open TEST.DAT"
- if $ERRORLEVEL = 2 msgwind "Increase FILES= in your CONFIG.SYS"
- exit
- endif
-
- The error above would most likely be due to the fact that TEST.DAT didn't
- exist in the current DOS directory, but it could also mean that DOS is
- simply out of file handles and that the user must increase the FILES=
- statement in the CONFIG.SYS file.
-
- NOTE 3: FOPEN allocates a memory buffer for file input/output, and only
- writes to disk if/when the buffer fills up, or if FCLOSE or FFLUSH is
- called. FFLUSH immediately writes all data from the memory buffer to
- disk... unless a disk cache is in use. Disk cache write-ahead buffers
- intercept calls to write to disk and do it in their own time... and
- there's nothing you can do to prevent that, other than turning off the
- write-ahead buffer of the disk cache by reloading it with the proper
- command line switch.
-
- 'Buffering' data in this manner makes the disk read/writes more
- effecient. On reads, FGETS (or even FGETC to get a single character)
- will initially read in 512 bytes of the file to an internal buffer. When
- you call FGETS/FGETC again it simply gets the data from the memory buffer
- instead of going to the disk again, which is much faster (the disk can't
- read less than 512 bytes [one sector] anyway). If a file was written to
- (FPUTS, FPUTC, etc), by calling FCLOSE you cause any data in the write
- buffer to be written to disk. I.e. FFLUSH is performed automatically
- when you FCLOSE the file. In either read or write mode, you also free up
- the memory that is used for the read/write buffer when you call FCLOSE.
-
- Though the script processor will automatically FCLOSE any files you left
- open when your script finishes, you should burn it into your brain now to
- *always* call FCLOSE. When you write your scripts enter the FCLOSE while
- you're thinking about it:
-
- FOPEN f1 "\temp\myfile.txt" "w"
- FCLOSE f1
-
- Then go back and fill in the FGETS or FPUTS command(s) *between* the
- FOPEN and FCLOSE, just to make sure you don't omit it (this technique
- also works well with IF/ENDIF, WHILE/ENDWHILE, etc). There are
- consequences in failing to FCLOSE an open file... If you attempt to
- DELETE a file that is currently open, you can cause the computer to lock
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 53
-
-
-
- up, or can cause an "exception 13" (which requires a re-boot) if the
- script is running on a 386 processor or better. So always FCLOSE a file
- as soon as you're done with it, to avoid such problems, and also to free
- up the memory buffer FOPEN allocates for file buffering... and the file
- handle DOS is using to keep track of the open file.
-
- YET ANOTHER NOTE: File access is limited to the script from which the
- file was FOPENed. You cannot FOPEN a file in one script, call another
- script with the SCRIPT command, and then attempt to access the same open
- file in the second script, using the same file handle (even if you use
- the GlobalStr array to store the file handle). If you must access the
- same file data in two or more scripts you must FCLOSE the file before
- calling the second script and FOPEN it again in the called script.
-
- 5.3 Testing for End-of-File
-
- If FGETS is successful (it was able to read data from the file) it sets
- $ERRORLEVEL to 0. When you reach the end of the file, FGETS will set
- $ERRORLEVEL to 1. To read an entire file, you'd do it from a WHILE loop,
- testing $ERRORLEVEL in the loop:
-
- WHILE 1 ;enter an endless loop (until a BREAK is found)
- fgets s f1
- if $ERRORLEVEL <> 0 BREAK ;if $errorlevel is not equal to 0
- print s
- ENDWHILE
-
- 5.4 How to store settings on-disk
-
- If your script needs some sort of "main setup" data similar to
- Intellicomm's main setup or BIF information, you can use the File I/O
- commands to permanently store the settings. How you do this is really up
- to you, and there is no "fixed" way of storing data on-disk. If you had
- two "Yes/No" settings, you could store them on-disk like this:
-
- variable setting1 "Yes"
- variable setting2 "No"
- variable mydatafile $HOME_DIR "MYSCRIPT.INI" ;C:\ICOM\MYSCRIPT.INI
- variable f
-
- ;here you could prompt the user for the Yes/No settings and store
- ; the result in 'setting1' and 'setting2'.
-
- ;later, to permanently store the settings...
-
- FOPEN f mydatafile "w" ;create or overwrite MYSCRIPT.INI
- FPUTS f setting1 ;writes "Yes" (no quotes) to MYSCRIPT.INI
- FPUTS f setting2 ;writes "No" (no quotes) to MYSCRIPT.INI
- FCLOSE f
-
- ;each time your script started you could get the settings easily
-
- FOPEN f mydatafile "r" ;open for reading
- if $errorlevel = 0 ;opened okay?
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 54
-
-
-
- FGETS setting1 f ;store Yes/No in setting1
- FGETS setting2 f ;store Yes/No in setting2
- FCLOSE f
- endif
-
- ;and finally, later in your script when you want to test a setting
-
- if setting1 = "Yes"
- ;do something if yes
- else
- ;do something else if not
- endif
-
- You needn't store the words "Yes" and "No" though, and storing numbers
- works just as well. Zero (0) is a standard way of saying "No" (or FALSE)
- in computer programs, while non-zero is a standard way of saying "Yes"
- (or TRUE). Thus you could substitute "Yes" and "No" above with 1 and 0,
- and save disk space (maybe... disks allocate space in large chunks and
- often it makes no difference whether a file has 1 byte or 1,000 bytes --
- the same space must be allocated regardless) and speed up your script a
- bit since numeric comparisons are faster than text comparisons:
-
- if setting1 <> 0 ;not equal to zero means "Yes"
- ;do something if yes
- else ;else (zero) means "No"
- ;do something else if zero (no)
- endif
-
- If you have multiple conditions, and not just Yes/No, just invent your
- own system where 0 means one thing, 1 means another, 2 means another,
- etc.
- The format of the information you store in your data files is totally up
- to you, and it's half the fun of designing your own programs.
-
- 5.5 Moving the File Pointer (Advanced Use Only)
-
- To move the 'file pointer' of an open file (the thing that keeps track of
- where FGETS will read from the file, and where FPUTS will write to next)
- you can either FCLOSE and FOPEN the file again, which starts you back at
- the beginning (or at the end if you open for "a"ppending), or use the
- FSEEK command to move the pointer to a specific position without closing
- the file. FTELL is FSEEK's companion, and it tells you where (at what
- byte number in the file) the pointer currently is, if you need to know.
-
- FSEEK seeks to an absolute byte in the file (byte 0 being the first
- character in the file), INCLUDING all the carriage returns and line feeds
- in the count. The only time it's of use is either when you know the
- exact byte count to the data you need (you've designed the data file
- yourself and have counted how many bytes there are to the position you
- desire, and accounted for all the CR/LF's), or when you use the STRPAD
- command with all your data before FPUTSing to the file, so that each line
- (or 'record' ... it might be a group of lines) is the same length. If
- all lines in the file are the same size, you can then just MULtiply by
- the line/record length (plus the CR/LF), and FSEEK to the beginning of an
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 55
-
-
-
- exact line/record in the file.
-
- The best way to understand this is to look at the file in the same way
- the file I/O routines do. They don't see a file line-by-line, they see
- it as a single 'stream' of characters:
-
- 1 2 3
- 01234567890123456789012345678901 <-- Numeric Ruler for reference
- only.
- Line 1||Line 2||Line 3||Line 4|| <-- Data in the file
-
- (The || above denote the CR/LF at the end of each line, the numeric ruler
- denotes the positions of each character in the file.) So, looking at the
- numeric ruler above, to FGETS line 1 you have to FSEEK to position 0. To
- FGETS line 2, you have to FSEEK to position 8, line 3 is at position 16,
- and line 4 is at position 24. All are multiples of 8, since each line is
- 8 characters long, counting the CR/LF at the end of each line.
-
- To get any line out of the file above, you just DECrement the line you
- want by one, then multiply by 8. If you want line 1, you multiply 0 by 8
- (0 x 8 = 0), if you want line 4 you multiply 3 by 8 (3 x 8 = 24).
- Decrement the line number, then multiply by the line length. Of course,
- this only works if all lines are the same length... which is why
- databases force you to define the length of each item before you store
- any data in the file. By keeping each data item a specific length, it's
- easy to locate a single piece of information out of the middle of a file.
-
- For an illustration, let's assume you were storing a list of names and
- you wanted later to be able to seek to the fifth name, or the tenth name,
- etc., on request. If you pad each name with spaces before you write it
- to disk, so that each line of the file is exactly 32 bytes long (30 for
- the name, 2 for the CR/LF), you can later get any name easily:
-
- variable name
- variable f
-
- FOPEN f "C:\MYDIR\NAMES.DAT" "a" ;open for "a"ppending (add to)
- printnc "Enter a name: "
- gets name 30
- strpad name " " 30 ;pad the right side with spaces to ensure 30
- ; characters ... STRPADL pads on the left side
- FPUTS f name ;write the data, followed by CR/LF
- FCLOSE f
-
- You could then retrieve any line from the file by decrementing the line
- (record) you want, multiplying by the line length (record length), then
- FSEEKing to that position prior to calling FGETS.
-
- variable linenum
- variable bytecount
- variable name
- variable size
-
- printnc "Which name (record number) do you want? "
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 56
-
-
-
- gets linenum 5 ;allow 5 characters for input (a number)
- dec linenum ;linenum = linenum - 1
- mul bytecount linenum 32 ;bytecount = linenum x 32 (32 = line len).
-
- ;now 'bytecount' holds the absolute byte count to the beginning of
- ; the line. If the user entered 1, we'd have decremented to 0,
- ; multiplied by 32, and ended up with 0 (32 x 0 = 0, the first byte of
- ; the file which would also be the start of the first line). If the
- ; user entered 2, we'd decrement to 1, multiply by 32, and end up with
- ; 32 (32 x 1 = 32, the position of the SECOND line), and so forth.
-
- FILESIZE size "C:\MYDIR\NAMES.DAT"
-
- ;FILESIZE gets the size of a given file on disk and stores it
- ; in a variable
-
- if size < bytecount ;file size less than bytecount?
- print "No such record."
- return
- endif
-
- FOPEN f "C:\MYDIR\NAMES.DAT" "r" ;open for "r"eading
- FSEEK f bytecount 0 ;seek to the bytecount obtained above
- FGETS name f ;get the line at bytecount
- STRTRIM name ;trim off the trailing spaces
- print "Here is the name you requested:"
- print name
- FCLOSE f
- return
-
- The 0 following 'bytecount' in the FSEEK above specifies where in the
- file you want to seek FROM. 0 means to seek from the BEGINNING of the
- file, which is what we want in this case. If 1 was specified after
- 'bytecount' instead of 0, FSEEK would seek ahead 'bytecount' bytes from
- the CURRENT position of the file pointer (which would still work, since
- the file had just been opened, and thus the 'current' position was the
- beginning of the file). If 2 was specified FSEEK would seek ahead from
- the END of the file. It's legal to seek past the end of the file, but
- you end up with garbage in the file from the original end-of-file to the
- position you seek to. An easy way to GET to the end of the file,
- actually, is to use
- FSEEK fhandle 0 2 (seek 0 bytes from the end of the file... it just moves
- the pointer to the end and leaves it there).
-
- You can also specify negative numbers in FSEEK to seek X number of bytes
- BACKWARDS from the end of the file, or from the current position.
-
- FSEEK f -500 2
-
- The FSEEK above seeks 500 bytes back from the END of the file.
-
- FSEEK f -32 1
-
- The above would seeks 32 bytes back from the CURRENT position. You
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 57
-
-
-
- cannot seek past the beginning though. If you attempt to, the file
- pointer will stop at the beginning of the file.
-
- Now, before we conclude the introduction and get to the more advanced
- techniques, we might as well mention the only file I/O command we haven't
- mentioned as yet: FPUTSNC. By now you should be quite clear on the fact
- that FPUTS writes CR/LF characters to terminate the line after the data
- you specify. In most cases this is what you'll want, but in some cases
- you might want to write data to the file WITHOUT putting a CR/LF after
- it. When this is the case, use FPUTSNC (NC meaning 'N'o 'C'arriage
- Return). It simply writes the data you specify, and does not terminate
- the line with CR/LF.
-
- One more little tidbit: If you have to (or want to) write control
- characters, such as your own CR/LF's to a file, just look up the control
- character in the "ASCII Codes" online help line in Icom (available from
- the help index and the "Script Language" index). Control characters are
- specified by preceding the character with a caret; CR is ^M (Ctrl-M) LF
- is ^J (Ctrl-J), etc. To write them (or any other control character) to a
- file:
-
- FPUTS f "Write this, then a blank line.^M^J"
- FPUTS f "Now write this."
-
- After executing the above, you'd end up with this in the file:
-
- Write this, then a blank line.
-
- Now write this.
-
- The ^M^J terminate the first line, FPUTS adds its own ^M^J, and the
- result is a blank line. You could accomplish the same thing with this:
-
- FPUTS f "Write this, then a blank line."
- FPUTS f "" ;write nothing, then ^M^J
- FPUTS f "Now write this."
-
- More details (and examples) on using FOPEN, FCLOSE, FGETC, FGETS, FPUTC,
- FPUTS, FPUTSNC, FSEEK, and FFLUSH can be found in the Detailed Command
- Summaries in SCRIPT.DOC when you need to refresh your memory. It's too
- bad we don't have hard drives and file I/O routines built into our
- brains....
-
- 5.6 Opening a File for Reading AND Writing (Advanced use only)
-
- By adding a plus sign (+) to the file FOPEN mode you are allowed to both
- read from (FGET) AND write to (FPUT) a file without closing it and re-
- opening it. Examples:
-
- FOPEN f "MYFILE.DAT" "r+" ;open MYFILE.DAT for read/write (file must
- ; exist)
- FOPEN f "MYFILE.DAT" "w+" ;create MYFILE.DAT, allow reading and writing
- FOPEN f "MYFILE.DAT "a+" ;create or append to MYFILE.DAT, allow reading
- ; and writing
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 58
-
-
-
- Opening a file for both reading and writing is an advanced technique that
- is not recommended until you have some experience with file I/O. Unless
- you totally understand the 'file pointer' concept and FSEEK command,
- you'll end up writing data all over the place in the file, possibly
- overwriting useful data: Though you CANNOT overwrite data in other files
- no matter where you FSEEK to, unless there's something wrong with your
- disk. If you FSEEK past the end of the file, DOS simply thinks you're
- trying to add to the file, and it looks for FREE disk space to write any
- new data (and if it doesn't find any, it doesn't write any data and the
- FPUTS will fail). DOS will *never* use the disk space that another file
- is using, unless the other file was previously deleted, or unless your
- disk or disk drive is malfunctioning (in which case you're going to lose
- data anyway, whenever anything else writes to the disk).
-
- In read/write mode, the file pointer keeps track of both where the file
- will be read from AND written to next. Since you'll almost never want
- data written at the point where the last read (FGETS/FGETC) left off, as
- a safeguard you must call FSEEK before you switch from reading to writing
- (from FGETS/FGETC to FPUTS/FPUTC) or vice versa. If you start writing to
- the file, then want to switch to reading, you must also call FSEEK or the
- read(s) will fail, and vice versa if you switch from writing to reading.
-
- Normally, you will read several lines out of the file, then go to another
- position in the file (FSEEK) and write data elsewhere (or vice versa...
- keep this "vice versa" business in mind so I don't have to say it every
- time. <grin>).
-
- For example, you may wish to open a file for "r+" which opens it for read
- write (as opposed to "w+" which destroys the file's contents if it
- exists) and update a specific record in the file by FSEEKing to it, then
- FPUTSing over the old data (remembering to pad the item with spaces so
- that it overwrites ALL of the existing data in the file... more on this
- in a second).
-
- If you truly do wish to switch from read to write (the vice versa is
- still in play), WITHOUT moving the file pointer just use 'FSEEK f 0 1'
- (seek zero bytes from the current position... or leave the pointer where
- it is). Here's an example of reading/writing with a single FOPEN:
-
- variable s
- variable f
-
- FOPEN f "\TEMP\TEST.DAT" "w+" ;create TEST.DAT, allow reading/writing
-
- FPUTS f "Line 1"
- FPUTS f "Line 2"
- FPUTS f "Line 3"
-
- FSEEK f 0 0 ;seek 0 bytes from the beginning (1st byte in the file)
-
- FGETS s f
- print s ;prints Line 1
- FGETS s f
- print s ;prints Line 2
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 59
-
-
-
- FGETS s f
- print s ;prints Line 3
-
- FSEEK f 8 0 ;seek to 8 bytes from the beginning (start of Line 2)
- FPUTS f "Item 2" ;overwrites 'Line 2' with 'Item 2'.
- FCLOSE f
-
- If you FPUTS a line that is LONGER than the previous line in the file
- (e.g. FPUTS f "This is line 2") then you'd overwrite the CR/LF at the end
- of the previous 'Line 2' and can overwrite the beginning of 'Line 3' as
- well. If you write a line that is SHORTER than the existing line, then
- some of the old data remains intact. If we used:
-
- FSEEK f 8 0 ;seek to start of line 2
- FPUTS f "2" ;write a 2 at the beginning of line 2
- FCLOSE f
-
- If we did this instead where we overwrote "Line 2" with "Item 2" above,
- we'd end up with "2||e 2" in the data file... (where || denote the CR/LF
- written by FPUTS) since it didn't overwrite the entire line. The "e 2"
- after the CR/LF is the remainder of the old "Line 2".
-
- It works no differently than using Typeover mode in your text editor or
- word processor. Think of the file as a SINGLE line of characters, and
- imagine what would happen to that line if you loaded it into your Editor,
- moved the cursor to a specific position (FSEEK), turned on Typeover mode
- and started typing. That's what FPUTS is doing when you FSEEK to a
- specific position and start writing. There is no way to 'insert' data
- into an existing file on-disk (though you can pretend you did... more on
- that in a second), anymore than you can 'insert' data on your video tapes
- or cassette tapes without overwriting what was there previously. Again,
- if you STRPAD your data before writing it, you'll always have a few
- blanks at the end of the line to store longer items later. And if you
- STRPAD shorter lines, you won't end up with the remainder of the existing
- (longer) data as was illustrated above.
-
- 5.7 Upating an Old Data File
-
- The only way to change the existing structure (line length) of a text
- file is to FOPEN the existing file for reading, read each line, pad it to
- a longer length, then write the data to another file (similar must be
- done to add new lines between existing ones):
-
- variable datfile $HOME_DIR "TEST.DAT" ;C:\ICOM\TEST.DAT
- variable tmpfile $HOME_DIR "TEST.$$$" ;C:\ICOM\TEST.$$$
- variable dat ;for file handles
- variable tmp
- variable s ;for file data
-
- FOPEN dat datfile "r" ;open TEST.DAT for reading
- FOPEN tmp tmpfile "w" ;create/overwrite TEST.$$$
- if $errorlevel <> 0 exit ;exit if error opening either file
-
- while 1 ;endless loop (until BREAK)
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 60
-
-
-
- FGETS s dat ;read in a line from TEST.DAT
- if $errorlevel <> 0 break ;end of file? (no data in 's' if so)
- strpad s " " 50 ;pad it to the new length
- FPUTS tmp s ;write the longer line in TEST.$$$
- if $errorlevel <> 0 ;uh oh... we ran out of disk space
- fclose tmp ; close 'em up, and avoid that
- fclose dat ; DELETE datfile below like the plague
- delete tmpfile ;we can't use this anymore, lose it
- print "Disk full. Aborting."
- exit
- endif
- endwhile
-
- fclose tmp
- fclose dat
-
- delete datfile ;delete TEST.DAT
- rename tmpfile datfile ;rename TEST.$$$ to TEST.DAT
-
- So, if you ever wondered what those .$$$ files were that you found lying
- around on your disk, now you know. A program either forgot to clean up
- its temporary file (I hope it wasn't Intellicomm), or perhaps the power
- went out or the machine hung before it got a chance to delete it. The
- extension .$$$ is often used to avoid overwriting useful files. You
- 'could' use the filename "ICOM.EXE" for your temporary file, but TEST.$$$
- (or anything .$$$) is probably safer.
-
- Experimentation is the best way to get a feel for file I/O. Create a
- dummy text file to play around with, and run a few FGETS/FPUTS tests on
- the file to see what happens (load the text file into the editor and look
- at it after each test). "Seeing is believing" and you really have to
- experience file I/O first-hand to get a good feel for it.
-
- REMEMBER:
-
- o Always either perform a CHDIR to get to the proper drive/directory, or
- specify the full D:\PATH\FILENAME.EXT in FOPEN when you use it.
- Otherwise the CURRENT DIRECTORY is assumed, which could be painful if
- you FOPEN for "w"riting, and are using a common filename... and an
- important file of the same name exists in the current directory.
-
- o Never attempt to DELETE or RENAME an open file.
-
- o Make sure the file pointer is at the proper position before you FPUTS
- (or FPUTSNC, FPUTC) to overwrite old data in an existing data file.
- You can only do this if you know the exact format of the data file
- (i.e. if you created it yourself or otherwise have a reliable way of
- knowing) and use FSEEK prior to the disk write to move the file pointer
- to the proper position. Once you FPUTS you cannot UNFPUTS, and an
- FFLUSH will only ensure that the data is written to disk faster.
- Further, if you overwrite existing data, the NEW data must be of the
- same length as the old data (or must be padded with spaces), or you
- will either overwrite the beginning of the next line, or will end up
- with a portion of the old data after the new data.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 61
-
-
-
- o FPUTS writes a Carriage Return/Line Feed after data, and FGETS uses
- this CR/LF to determine when to stop reading data from the file (it
- reads one line, and stops when it hits the LF). You must take the
- CR/LF into account when calculating byte counts with FSEEK.
-
- o Always FCLOSE a file as soon as you're finished reading/writing to it.
-
- o Pat yourself on the back. These same concepts (though in slightly
- different syntaxes) are used for file I/O in all computer programs, and
- all programming languages. If you got through all of the above, and if
- you actually practice it and succeed, you could consider yourself a
- fairly able computer programmer.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 62
-
-
-
- 6. INTRODUCTION TO DATABASE COMMANDS (FILE TAGGER CATALOGS)
-
-
- This section introduces you basic database concepts and will help you to
- make effective use of the script database or "File Tagger Catalog
- oriented" commands. The material is somewhat advanced (though not
- terribly so), and you should have a basic grasp of scripts such as
- variables, the ASSIGN command, WHILE loops, etc., before you tackle this
- section.
-
- 6.1 Why would I want to use the catalog-oriented commands?
-
- The main purpose of the catalog-oriented commands is to allow you to
- perform customized maintenance on your Tagger catalogs. Using job Custom
- Commands, or the PREJOB.SCR, PREDOWN.SCR or POSTFILE.SCR scripts (see
- "Automation in Detail" in the Icom online help for details on these
- scripts) and executing a script prior to a Call to a BBS, you could scan
- a given Tagger catalog and automatically Tag (or Untag) certain files, or
- set Transfer Days (the day of the week on which to transfer the file)
- based on file criteria such as the filesize. Or, you could add up the
- total number of bytes of all Tagged files and change the tag status of
- certain files to a special tag of your own which would allow you to
- temporarily untag the file and re-tag it later after the job completed,
- and so forth. Or you could modify the description (or any other
- attributes) of files after downloads by adding to POSTFILE.SCR. In
- short, by getting a handle on the File Tagger-oriented commands, you'll
- gain absolute and total control over your File Tagger catalogs, in every
- imaginable way, in most every aspect of use.
-
- Many requests have come in for specialized File Tagger catalog handling
- that really wouldn't benefit the majority of Intellicomm users, but
- certainly would be helpful to those people who made the requests. Using
- the catalog-oriented commands, you can handle almost any specialized
- catalog-oriented task you can dream up -- and you can handle it exactly
- as YOU need it done, without being forced to use "pre-fabricated"
- ICOM.EXE routines which might not do exactly what you want.
-
- 6.2 What is a Database?
-
- Databases (and File Tagger Catalogs which are dBASE-compatible
- databases), in the context we are interested in here, are files that hold
- information on-disk in a specific format. They are made up of simple
- units called "fields" and "records":
-
- "Field 1, Record 1" |
- "Field 2, Record 1" |---- RECORD 1
- "Field 3, Record 1" |
-
- "Field 1, Record 2" |
- "Field 2, Record 2" |---- RECORD 2
- "Field 3, Record 2" |
-
- ...etc. Each record contains a given number of fields, and each field
- holds a specific type of information, of a specific length. In File
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 63
-
-
-
- Tagger catalogs, the "fields" are the filename, file date, import date,
- description, etc., and each "record" holds information about ONE file
- that exists on a BBS (if accessing the NEWFILES catalog, which holds BBS
- new files listings) or on your disk (if accessing the FILELIST catalog,
- which keeps track of the files Icom auto-downloads to let you re-upload
- them to other BBS's).
-
- The importance of keeping each field a specific length, as opposed to
- storing data all different lengths, is that it makes it very easy (and
- fast) to access any given record in the database. Since each field is a
- fixed size (regardless of the actual data being stored in the field),
- each record is the same size and thus the position of any given record in
- the file is easy to obtain. If the combined length of all fields in all
- records is 50 bytes, and we want record #10, we simply multiply 50 by 10
- to find the position of the record, in the database file.
-
- If the fields/records were NOT all the same size, it would be difficult
- (and slow) to pull a given record out of the database, since we'd have to
- start at the beginning, and 'count' records (perhaps using a special
- character between each record so we knew where each record ended) until
- we got to the one we wanted.
-
- dBASE-compatible databases (and File Tagger Catalogs) use the file
- extension .DBF (e.g. NEWFILES.DBF, FILELIST.DBF, etc), and each record in
- the file has a number starting at record #1, up to a maximum of (about)
- record #2 billion. To get at any of the records, we (or something else,
- such as the indexes discussed below) must first know the record number.
-
- In File Tagger catalogs, record #1 is reserved for a "header" record,
- which is where the Tagger saves information such as the bookmark
- position, the current View Date of the catalog, the sort order and
- direction as set by the user, etc. The header record is no different
- than any of the other records (it has the exact same fields... it has
- to), other than the fact that the File Tagger reserves it for its own
- use, to store information. You cannot access record #1 directly, though
- you can update most of the information in the header (such as the catalog
- sort order, bookmark position, current view date, etc) with special
- script commands which are outlined later in this section.
-
- The rest of the records in the File Tagger catalogs hold information
- about files, such as the filename, date, size, whether the file is Tagged
- for transfer or not, etc.
-
- 6.3 Indexes
-
- Database index (.NDX) files are special files which allow easy sorting of
- one particular .DBF database in a specific way. When new records are
- added to a database (.DBF), they are not 'inserted' into the existing
- record structure, but rather are simply added (appended) to the END of
- the .DBF file. If you have 10 records in your database, and add one, the
- new record becomes record #12 (12 because record #1 is used as a header,
- as mentioned above. The header (record #1) plus 10 existing records
- (records 2-11), plus the new record #12).
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 64
-
-
-
- However, as mentioned above, to get a specific data record from the
- database, we must have the record number. Now suppose you want to get
- all the Tagged records out of a Tagger Catalog that has 5,000 records in
- it. We already know that the .DBF itself doesn't sort the records in any
- specific way, and simply appends new records to the end ... so do we have
- to read record #2, check for a Tag, then read record #3, check for a Tag,
- all the way up to 5,000 records? Thankfully, no, since it would be very
- time-consuming (and disk-punishing) to do so. This where the .NDX files
- come into play.
-
- When an .NDX is in use the .DBF file is NOT accessed in its natural
- record order. When you access the 'first' record in the database, you
- might get record #5,000 while the 'last' record might be record #25.
- I.e. the indexes give us the proper .DBF record numbers needed to display
- (or otherwise manipulate) the database according to a specific sort
- order. When an NDX is in use, the database routines jump all over the
- database, perhaps grabbing record #5, then record #50, then record #12,
- etc., though this is mostly invisible to you.
-
- How the NDX's actually accomplish this sorting is not important: The
- important thing to understand is that when an index is in use, the
- 'first' record in the database is not necessarily record #1 (or #2 in our
- case, since record #1 is reserved for the header). The 'first' record is
- simply the record that happens to sort first (alphabetically,
- chronologically, or otherwise, according to how the index is defined),
- given a specific sort order, as compared to all the other records in the
- database. The indexes do all the sorting, and it takes zero work on your
- part. It is important to understand the CONCEPTS behind indexes, since
- sometimes you WILL be involved with the actual database record numbers,
- and it could be confusing to see record #5,000 coming 'first', then
- record #10 coming 'next', etc., were you not aware of how the .NDX(s) and
- .DBF work together.
-
- 6.4 Using File Tagger Indexes
-
- The File Tagger maintains three index (.NDX) files per File Tagger
- catalog, and stores them all in the same directory as the .DBF itself
- (the $DBF_DIR System Variable can be used to access the proper
- directory). The indexes use the same base name as the catalog
- ("NEWFILES" is the "base" name of the NEWFILES.DBF database), but replace
- or add a new letter at the end of the base name. Below we'll use the
- base name NEWFILES to illustrate the filename of each index (you don't
- "have" to know the .NDX filename except when you want to delete a
- catalog, or rebuild a damaged index):
-
- 1. "Tag Status/Location" (NEWFILET.NDX ... replaces the "S" at the end
- of NEWFILES with a "T" since the filename is already 8 letters; "T"
- for "Tag Status"), used to easily get all the Tagged (or Noted, or
- Untagged) files for a specific BBS.
-
- 2. "Catalog Date/Filesize (NEWFILEC.NDX ... "C" for Catalog Date), the
- oldest records to the newest records, the smallest to the largest.
- This index makes for quick and easy purging (deleting) of older
- records. The "Catalog Date" is the date on which the record was
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 65
-
-
-
- added (imported to) to the database.
-
- 3. "Filename/File Date" (NEWFILEF.NDX ... "F" for Filename) all
- filenames in the database, in alphabetical order. This index makes
- for quick duplicate checking (so we needn't search filenames of all
- the records in the catalog when importing) and other filename
- searches.
-
- The script COPEN command ("C"atalog OPEN; all catalog-oriented commands
- begin with "C" for Catalog) opens the .DBF (database), all three
- associated indexes, and the .DBT (standard dBASE "memo" file which holds
- the extended descriptions of files). If any or all of the .NDX files are
- missing, COPEN automatically builds new ones. And thus a handy way to
- build new indexes, if the need ever arises, is to simply use the DELETE
- command to delete the one or more .NDX files (after the catalog is
- CLOSED; do not delete open NDX files), then call COPEN and it will build
- new ones based on contents of the .DBF file.
-
- IMPORTANT: When an existing record is deleted from the database
- (permanently in a CPACK, not when it's just flagged as "Deleted"), or a
- new record is added, all three .NDX files are *automatically* updated or
- rebuilt entirely to insert the new record data in the proper place
- according to each index sort order. You will never work with an .NDX
- file directly ... it's all taken care of automatically by the File Tagger
- (and the Tagger-oriented script commands), as new records are added, and
- old records are deleted. I.e. you never have to "maintain" an .NDX from
- your script. You simply "use" them (by setting a sort order with the
- CSETSORT command), and let Icom take care of the boring maintenance
- details.
-
- 6.5 How this all applies to Scripts
-
- Accessing a File Tagger catalog is much the same as accessing a regular
- text file with the File I/O script commands:
-
- 1. Open the catalog with COPEN.
- 2. Set the sort order (.NDX) if necessary with CSETSORT. Note that all
- three of a catalog's NDX files are 'opened' when you perform a COPEN,
- and CSETSORT simply switches from one index to another.
- 3. Use CGETREC to read the first record. The next call to CGETREC gets
- the next record, etc, according to the sort order (index) you set with
- CSETSORT. Again, the 'first' record changes from sort order to sort
- order, and most likely will NOT be record #2 (the first valid record
- in the database, due to the header) in the .DBF file. After you CGET
- a RECord ('get' meaning load it from disk into memory) you can modify
- it and write it back to the database (CPUTREC) or can display it, Tag
- it, Note it, Untag it, etc. *Until* you CGETREC a record from the
- database you can't do a thing with it: the record must be loaded from
- disk into memory before you can access or manipulate it.
- 4. Close the catalog (when finished) with CCLOSE.
-
- When you use CGETREC to load a record from the database (again, 'load'
- meaning that it is read from the database on-disk and loaded into memory
- where you can work with it), the record is split up into the "fields"
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 66
-
-
-
- mentioned at the outset. Each field goes into a different script System
- Variable as listed below. These fields listed below are exactly the
- fields you see when you "Edit" a record from within the File Tagger:
-
- $CTAG_FLD The tag status of the file (Tagged, Noted, Untagged). With
- inventive use of this field (if need be), you can set your
- own custom tags which will be meaningful to your script, but
- will be meaningless to Intellicomm itself when transferring
- files. $CTAG_FLD field normally holds a 'T' if the file is
- Tagged, an 'N' if the file is Noted, and a 'U' if the file
- is untagged. Icom ignores any letters from 'U' to the end
- of the alphabet, leaving you with several possibilities for
- "custom" tags which you might use to, say, automatically
- Untag a very large file, marking the $CTAG_FLD with the
- letter 'Z'. When Icom finishes transferring files (it will
- ignore your custom 'Z' tags), you can then go through the
- catalog looking for your 'Z' tags, and can then re-tag the
- files with the regular 'T' for Tag. You'll be able to
- understand how you might accomplish this better after you
- finish this chapter.
- $CDAY_FLD The transfer day, if set by the user or by a script. This
- field can be compared against the $DOW (Day of Week) System
- Variable to see if the file should be transferred 'today' or
- not. If $CDAY_FLD = "0" (Anyday, the default), the user
- cares not on which day the file is transferred. This one
- can also be used to force Intellicomm to ignore a Tagged
- file; Icom checks this field when transferring files, and
- won't bother with it if $CDAY_FLD doesn't match $DOW (the
- current day of the week).
- $CNAME_FLD The FILENAME.EXT of the file. No D:\PATH\ is ever stored in
- this field, even in the FILELIST (upload) catalog. Icom
- keeps a list of Upload Directories (defined in the Icom main
- setup on the "Filenames and Paths" screen; accessable from
- scripts via the $UL_PATH item) and looks in those
- directories to find files when uploading. You do the same
- with the LOCFILE (Locate File) script command.
- $CFDATE_FLD The file (or archive) modification/creation date, in
- standard dBASE date format: YYYYMMDD [Year, Month, Day]
- $CSIZE_FLD The size of the file.
- $CCDATE_FLD The date that the record was added to the catalog, in
- standard dBASE date format (the CATALOG DATE: this is what
- the "View Date" uses to filter out older files, and the View
- Date is still in effect when you access a catalog from a
- script ... though you can change the View Date from your
- script if need be).
- $CLOC_FLD The BIF ID/filename (the BBS that has the file). If you are
- online when your script is accessing the Tagger Catalog you
- can compare this field against the $BIF_NAME System Variable
- to see if the file exists on the BBS Icom is currently
- connected to.
- $CAREA_FLD The BBS conference/forum the file is in (NEWAREA $CAREA_FLD
- can be used if online to change to the proper BBS area;
- assuming the BIF is set up for it with the proper "Area
- Change" command on the BIF "File" screen).
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 67
-
-
-
- REMEMBER: CGETREC 'loads' a single catalog (.DBF) record from disk into
- memory (with each field from the record going into the variables listed
- above). Thus you cannot (if you want anything valid) access the above
- variables above *until* you COPEN a catalog, and use CGETREC to load a
- record from disk.
-
- There are two exceptions to this: During automated file transfers, and
- in the POSTFILE.SCR script (see the comments in POSTFILE.SCR included
- with Intellicomm). During automated file transfers Intellicomm will have
- already performed a COPEN (and perhaps a CGETREC) on the files it's
- automatically transferring. There are four places in the BIF where you
- can have a script called during automated file transfers (all are on the
- BIF "File" screen): the "Area Change" "Upload File[s]", "Download
- File[s]", and "Description [@SCRIPT]" slots. By entering @SCRIPTNAME in
- any of these BIF slots, Icom will run a script instead of sending a
- single command (as is the case with all BIF responses). The only place
- you really 'should' place a @SCRIPTNAME command during an automated file
- transfer, if necessary, is in the "Description [@SCRIPT]" command. The
- purpose of this is to handle entry of the file description (on uploads)
- in tricky situations where the usual description entry routine can't
- handle. If you call a script via this BIF slot, Intellicomm will already
- have performed a CGETREC, and the fields listed above (plus the
- description, outlined below) WILL contain valid values, without your
- opening the catalog with COPEN. If you do use a script during automated
- file transfers, DO NOT close the catalog (CCLOSE), or set the sort order
- to the Tag Status/Location index and move the pointer (i.e. perform a
- CGETREC) or Icom will lose its place.
-
- If you change any of the variables above after a CGETREC, you do NOT
- modify the actual record in the database -- you modify only memory
- variables. To modify a record permanently you must re-write the data
- back from memory to the disk using CPUTREC. This is typical of file I/O
- on computers, and you almost never work with a disk file directly, in any
- computer program (unless writing your own version of DOS). We "work"
- with the computer's memory (very fast), and use the disk (DOS file
- Input/Output; extremely slow in computer terms) only when permanent
- storage is required.
-
- You may notice above that the file DESCRIPTION isn't stored in a System
- Variable, and this because no script variable can hold more than 256
- characters of text in Intellicomm's script language; yet descriptions
- will often contain over 256 characters. Thus, CGETREC loads the entire
- description into a large internal memory buffer and two script commands
- -- CGETDESC and CPUTDESC -- are used to get a single line of the
- description from this buffer, and load it into a variable where you can
- work with it one line at a time.
-
- Again, CPUTDESC does not modify the description on-disk in the catalog.
- It simply affects the description (line by line) in an internal memory
- buffer. So you can 'CGETDESC myvariable 1' to get description line 1,
- modify it, then 'CPUTDESC myvariable 1' to write the modified line 1 back
- to the memory buffer (the old line is stripped first, so if you CPUDESC a
- blank line, you remove the original description line). To update a
- record (description included, as well as updating of the .NDX files) on-
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 68
-
-
-
- disk you must call CPUTREC.
-
- One more note on descriptions: When loaded into the memory buffer by
- CGETREC, descriptions are formatted to 45 characters per line (wrapping
- words that don't fit on the 45 character line, in the same way as a word
- processor does). After using CGETREC you can re-format the description
- to another line length by calling CFORMATDESC. For example you wanted 40
- character description lines you would:
-
- CGETREC ;get the record (more on this in a second)
- CFORMATDESC 40 ;format to no more than 40 characters per line
- CGETDESC somevariable 1 ;put description line 1 (now 40 chars or less)
- ; into variable 'somevariable'
-
- Now before you get completely lost, it's time for an example you can sink
- your teeth into. Let's display the NEWFILES catalog, sorted by Tag
- Status/Location. Displaying a catalog isn't something you're likely to
- do with a script (the File Tagger can most likely do a better/faster job)
- but the concepts of cycling through the catalog records are the same
- whether you're displaying them or downloading files, or checking and
- modifying records, or doing anything else. A good way to get practice is
- to go through a catalog DISPLAYING various things on the screen yourself,
- so you can get a feel for it. Make sure you read the comments (;) below:
-
- variable key ;first we need a few variables for use below
- variable tag
- variable name
- variable date
- variable desc
-
- wndopen "NEWFILES Catalog" 1 1 80 25 ;open a box to display in
- print " ^BFilename Date Description^B"
- window 2 3 79 24 ;so we don't overwrite the titles
-
- COPEN "NEWFILES" ;open the .DBF and its .NDX's
-
- ;Next, set the sort order. CSETSORT takes two parameters: the first
- ; is the sort order (-1 = unsorted, 1 = Tag Status/Location, 2 = Catalog
- ; Date/Filesize, 3 = Filename/File Date) and the second is the sort
- ; DIRECTION (0 [or nothing] = forward, 1 = reversed)
-
- CSETSORT 1 ;Tag Status/Location, FORWARD: Noted records come first,
- ; Tagged records come second, Untagged records come last.
- ; If we reverse the sort order, Untagged records come
- ; first, Tagged second, and Noted third.
-
- ;Note that if no parameters are specified after CSETSORT (or if you
- ; specify anything other than -1, 1, 2, or 3 as the sort order), the
- ; user is prompted to enter the sort order and direction (identical to
- ; when "Sort" is selected from within the File Tagger), which is a handy
- ; way to get user input when needed. Note also that CSETSORT does NOT
- ; change the sort order as saved in the catalog itself (i.e. the order
- ; the user has set). You must use CSAVESORT to save the sort order to
- ; the catalog header, if you want to keep the sort order 'permanently'.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 69
-
-
-
- ;If you do not call CSETSORT after COPENing a catalog, it will remain
- ; sorted in the same manner as the user had it set up the last time it
- ; was viewed, which probably isn't what you'd want. You can check the
- ; current sort order, if need be, by accessing the $CSORT_ORDER and
- ; $CSORT_DIR (direction) System Variables. They contain the same values
- ; outlined in the CSETSORT parameters listed above.
-
- while 1 ;enter an endless loop (until BREAK)
- CGETREC ;gets first (or next) record
- if $errorlevel <> 0 break ;end loop at end of catalog
- if $CTAG_FLD = "T" assign tag "^P" ;T = Tagged (^P = > as in Tagger)
- if $CTAG_FLD = "N" assign tag "Ø" ;N = Noted
- if $CTAG_FLD = "U" assign tag " " ;U = Untagged
- assign name $CNAME_FLD ;copy the filename into our variable
- strpad name " " 14 ;pad filename with spaces to 14 chars
- ;as mentioned earlier, $CCDATE_FLD and $CFDATE_FLD are stored in
- ; standard dBASE date format YYYYMMDD. We don't want to display the
- ; date like this, so we call CDATE2DATE to convert it to the usual
- ; date format/date separators the user has set up in the Icom main
- ; setup.
- CDATE2DATE date $CFDATE_FLD ;the result is stored in 'date'
- CGETDESC desc 1 ;get description line 1
- strblank desc assign desc "No description available"
- print "^B" tag "^B" name date " " desc ;print the data (^B is Bold)
- endwhile
-
- CCLOSE ;and close the catalog when done
- pause "^M^J^BPress a key..."
- wndclose
- return
-
- What happens above is that the commands between WHILE and ENDWHILE are
- executed over and over again, until the end of the catalog is found
- (CGETREC sets $ERRORLEVEL to 1 when it hits the end). So CGETREC is
- called repeatedly and each record is displayed, until the end of the
- catalog is found.
-
- When COPEN or CSETSORT are called, the 'record pointer' that CGETREC uses
- to know which record to get from the database, is automatically set to
- the 'beginning' of the catalog (the 'beginning' according to the sort
- order). After CGETREC gets the record and stores the data in the
- $CXXXX_FLD System Variables, it updates an internal record pointer (using
- the current .NDX) to point to the 'next' record, again, according to the
- current sort order. So each call to CGETREC gets the next record,
- according to the current sort order.... it couldn't be simpler.
-
- You can use the CTELL command to find out which database record number
- CGETREC got, and if you used CTELL in the loop above and printed out the
- record numbers, you'd probably see that CGETREC was jumping all over the
- database getting perhaps record #5, then record #30, then record #10,
- etc.
-
- You don't 'have' to know the current record number except in one case:
- when CDELREC is used to delete a record. For safety's sake, you must get
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 70
-
-
-
- (with CTELL) and specify a record number to delete when you use CDELREC.
- With most other catalog-oriented script commands that take a record
- number (several do, though optionally), if you OMIT the record number,
- the 'current' record (the last record obtained with CGETREC) is assumed.
-
- 6.6 The View Date
-
- As mentioned earlier, the View Date is still in effect when accessing a
- catalog from a script... which means that records with a $CCDATE_FLD
- (Catalog Date) *older* than the View Date ($VIEW_DATE) are filtered out.
- I.e. CGETREC ignores these older records. The one exception to this is
- if you use CSETSORT -1 (no sort order). In this case, the View Date is
- ignored, and database records are accessed in their raw order (as they
- were added to the .DBF), and CGETREC gets all records regardless of their
- Catalog Date.
-
- You can check and/or modify the View Date from your scripts by accessing
- the $VIEW_DATE System Variable. If you modify $VIEW_DATE, the date must
- be stored in standard dBASE format: YYYYMMDD (YearMonthDay). Examples:
-
- ASSIGN $VIEW_DATE "19900101" ;January 1st, 1990. Setting this View Date
- ; will ensure that ALL existing records
- ; are found by CGETREC (and CSEEK,
- ; discussed below). Intellicomm was not
- ; released by that date, so it's impossible
- ; for a record to have a catalog date older
- ; than 01/01/90.
- variable dbase_date
- DATE2CDATE dbase_date $DATE ;convert today's date to dBASE format
- ASSIGN $VIEW_DATE dbase_date ;only records imported today are found by
- ; CGETREC (and CSEEK), if an index is in
- ; use
-
- Note that neither ASSIGN $VIEW_DATE example above would change the View
- Date as saved in the catalog itself. If you wish to save View Date
- changes to the catalog header (i.e. so it will take effect the next time
- the user views the catalog, or the next time you open it with COPEN), use
- CSAVEVDATE.
-
- Note also that the File Tagger itself automatically updates the View Date
- to the current date ('today') when it imports BBS new files listings, so
- that the user only sees the new files that were imported. This is the
- date that $VIEW_DATE will be set to when you first COPEN a catalog: the
- date of the last import.
-
- The 'Auto View Date Update' on imports is a feature that can be turned
- off in the Icom main setup though (Tagger Settings), and you can also
- check that setting or temporarily shut it off in your script by accessing
- the "*afdate" Main Setup Variable (apologies for the 'f' ... The View
- Date was originally named the Filter Date, and 'af' stands for 'auto
- filter' date. Converting the tag in the ICOM.INI file from 'afdate' to
- 'avdate' wasn't worth the trouble). SAVEINI re-saves the Main Setup data
- to disk if you wish to permanently change this or any other Main Setup
- Variable from a script. See the Main Variable summary in SCRIPT.DOC for
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 71
-
-
-
- details on this or any other Main Setup Variable.
-
- 6.7 Getting Around in a Catalog
-
- You may have noticed in the main example above that while there are a
- couple of twists as far as fields and sorting goes, access to the
- database was sequential (one record after the other), much like reading a
- text file with FGETS. And just as you can move the file 'pointer' around
- with FSEEK when reading text files so that FGETS reads at a different
- position in the file, CSEEK allows you to move the 'record pointer' of
- the database so that CGETREC gets one or more records out of sequence.
- It works in much the same way as FSEEK (don't worry if you've never used
- FSEEK; it isn't mandatory for this discussion), except that you never
- need worry about the specific file positions, since the database
- structure does all the work for you.
-
- CSEEK takes two parameters: the first is "the number of records FROM
- whence" and the second is whence (0 = from the beginning of the catalog,
- 1 = from the present position, 2 = from the end of the catalog, 3 = from
- anywhere; it seeks to an absolute record number). Examples:
-
- CSEEK 0 0 ;seek 0 records from the beginning (take it from the top)
- CSEEK 10 0 ;seek to the tenth record from the beginning
- CSEEK 1 1 ;seek ahead (from current position) by one record
- CSEEK 10 1 ;seek ahead (from current position) by ten records
- CSEEK -10 2 ;seek ten records back from the end
- CSEEK 100 3 ;locate record #100 in the index (100 must be a valid rec#)
-
- As mentioned earlier, CSETSORT automatically puts you back at the top of
- the catalog (an automatic CSEEK 0 0 is performed after CSETSORT). If you
- want to change the sort order with CSETSORT, but DON'T want to lose your
- current position in the catalog, first GET your current record number
- with CTELL, then either use mode 3 of CSEEK (seek to an absolute record
- number) or specify that record number with CGETREC to re-load it, and to
- seek back to that record in the index:
-
- variable cur_rec ;use any variable to store the record number
-
- CTELL cur_rec ;stores current record number in 'cur_rec'
- CSETSORT 2 1 ;set a new sort order
- CSEEK cur_rec 3 ;seek back to the previous record number
- CGETREC ;gets record 'cur_rec' as stored by CTELL
-
- ;alternatively, you can do this
-
- CTELL cur_rec ;stores current record number in 'cur_rec'
- CSETSORT 2 1 ;set a new sort order
- CGETREC cur_rec ;"CSEEK cur_rec 3" implied before CGETREC
-
- It may seem like there's a valid need for this (and perhaps you'll find
- one... though the only place this sort of thing is used in Icom is when
- DISPLAYING the catalog to the user, and s/he changes the sort order... so
- we keep the pointer on the same record). But in most cases, once you
- change the sort order you might as well start back at the beginning,
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 72
-
-
-
- since the 'current' record (as reported by CTELL before the change in
- sort order), although it still has the same record number, will now be in
- a completely different position in the database, RELATIVE to where it was
- before the sort order was changed. If it was the 20th record previously
- (in relation to the 'top' of the catalog according to the last sort
- order), it might be the 50th record from the 'top' after a change in the
- sort order, or may the the last record in the database, or the first,
- etc. Further, the "next" and "previous" records before and after
- 'cur_rec' will not be the same as they would have been, had the sort
- order not been changed. Even the first and last records in the database
- will be different. [Speaking in relation to other records, according to
- the sort order. The database record numbers always remain the same, but
- the record numbers are mostly irrelevant when an index is in use.] Thus
- there's little use in going back to the same position after a re-sort,
- since it's not the 'same' position at all, and none of the other records
- that were around the current record previously will remain the same
- either.
-
- If you're confused, you can see this quite clearly by entering the File
- Tagger and selecting "Sort" (in a catalog that contains a screenful of
- records or more) to change the sort order. The 'pointer' remains in the
- same position, but all the records around the pointer change... and the
- position of the current record in relation to the 'top' of the catalog
- (as evidenced by the little box in the scrollbar, on the right border of
- the Tagger) changes as well. It's a whole new ball game after a change
- in the sort order, and thus normally you'll only perform *one* CSETSORT,
- just after the COPEN. In such a case, you'll also probably want to start
- at the top of the catalog, which is what CSETSORT automatically does.
-
- 6.8 Getting the Total Number of Records
-
- Before using CSEEK, you can get the total number of records in the
- database if necessary by checking the $CTOTAL System Variable. And, if
- an index is in use (if CSETSORT -1 is used, no index is in use) $CVTOTAL
- tells you how many records are visible according to the current View Date
- ($VIEW_DATE). In most cases, if using a sort order, $CTOTAL will not be
- the same as $CVTOTAL, since the View Date is normally set to filter out
- older records. Example:
-
- variable num_filtered
-
- ;Below is a 'SUBtract': num_filtered = $CTOTAL - $CVTOTAL
- ; This gives us the number of records that are currently being filtered
- ; out (or zero if none).
-
- SUB num_filtered $CTOTAL $CVTOTAL
-
- print num_filtered " records are hidden due to the View Date."
-
- The above displays the number of records that are currently being
- filtered out due to the View Date. Note that $CVTOTAL is calculated when
- you open (COPEN) a catalog, and is re-calculated whenever you change the
- $VIEW_DATE variable.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 73
-
-
-
- 6.9 The View Date and Tagged/Noted Files
-
- Tagged files are NEVER filtered out by the View Date, whether an index is
- in use or not. And Noted files are not filtered out by default, but that
- can be changed by the user in the Icom Main Setup on the File Tagger
- Settings screen. If "View Date Filters Noted?" is set to Yes in the Icom
- Main Setup, then the Noted files imported prior to the current View Date
- WILL be ignored (filtered out) by CGETREC and CSEEK, if an index is in
- use. You can change this if need be by accessing the *fnote (filter
- noted) Main Setup Variable:
-
- ASSIGN *fnote 0 ;View Date doesn't filter out any Noted files
- ASSIGN *fnote 1 ;View Date does filter out (older) Noted files
-
- If you modify this or any other Main Setup Variable, you must make sure
- to SAVE the previous value, and restore it when your script ends... or it
- will remain that way until Intellicomm is exited/reloaded, or until a new
- main setup file is loaded (LOADINI, or a manual "Load" via the Icom main
- setup menu). As with all variables, you are modifying memory locations
- and you do not change data on-disk when you modify a variable. You must
- use SAVEINI to update the Icom Main Setup file on-disk. See the Main
- Setup Variables section in SCRIPT.DOC for more details.
-
- There are many other catalog-related commands, including: CCLEARBUF
- (clears all the $XXX_FLD variables, and the file description memory
- buffer, perhaps to get ready to fill in a new record yourself before
- CADDREC), CDELREC, CEDITREC (same as "Edit" from the File Tagger; [PgUp]
- and [PgDn] can also be used to browse through the database), CEMPTY,
- CEXPORT, CFLUSH, CIMPORTNEW, CIMPORTTEXT, CNOTEREC, CPACK, CTAGREC and
- several others. They all are quite simple to use, and most just perform
- tasks you normally carry out right from the Tagger, so none should
- require much explaining if you understand the Tagger, and the material
- above. You can find all the necessary information, along with examples,
- in the Detailed Command Summaries in SCRIPT.DOC. To see a quick summary
- of all the Catalog-oriented commands, see the "Script Commands at a
- Glance" secion in SCRIPT.DOC.
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 74
-
-
-
- 7. USING THE SCRIPT DEBUGGER
-
-
- 7.1 What are BUGS, and What is a DEBUGGER?
-
- What! Bugs in MY script?! No matter how hard you try, no matter how
- careful you are about writing your scripts, somewhere, sometime you're
- probably going to run into a problem that you simply can't figure out.
- You'll look the script over and pull your hair out: everything will LOOK
- fine. You'll check the manual; you'll check your commands again, you'll
- check the manual again ... and just before you're ready to throw your
- computer out the window you'll remember the Debugger!
-
- Debuggers aren't designed to find your programming errors for you:
- they're designed to slow your program down (or script, in this case), run
- it step-by-step, show you each command before it gets executed, and show
- you the results of each command (screen output, etc) after it is
- executed. Sometimes it's the only way to pick up subtle errors... and
- subtle errors can sometimes create large problems.
-
- Bugs are not syntax errors such as misspelling a command/variable or the
- like: Icom will pick those up and abort the script, pointing the error
- out to you. Bugs are logic errors, where you're perhaps meaning to see
- if something is less than or equal to a number... and you're instead
- (unintentionally) telling Icom to check whether the number is GREATER
- than or equal to the number. Or you have two variables called X and Y,
- and you use Y when you meant to use X, and so forth. These sorts of
- errors cannot be picked up by Icom's script processor (or any programming
- language for that matter), since it trusts that you know what you're
- doing... It doesn't second-guess you, and has no way of knowing whether
- you REALLY wanted to use X when you used Y, or wanted greater than (>)
- and used less than (<) by mistake. This is where the debugger comes in.
-
- Here are some examples of the kinds of bugs you're likely to run into,
- that you can find with the debugger:
-
- 1. Garbage In Garbage Out. This means that if the data you're using is
- garbage (not valid) then the results you'll get will also be garbage.
- It applies to anything that uses any sort of data (script command
- parameters and all script variables are 'data') to perform a function.
- The debugger can help eliminate this problem by showing you the
- CONTENTS of variables (the data), before the script command acts upon
- the data. A common mistake is to inadvertently change the contents of
- a variable somewhere else (in the same script; a subroutine perhaps)
- without realizing it. You'll *think* that a certain variable is
- holding a certain value... but you'll have forgotten that the same
- variable is used elsewhere in the script, and is thus modified
- elsewhere. By using the debugger you can follow the script step-by-
- step to find where your data is corrupted.
-
- 2. Another common error is to forget to initialize one or more variables
- before entering a loop. If you were using a variable called 'count',
- and you had previously been using 'count' for something and its value
- was now higher than 10, then this loop below would NOT execute at all:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 75
-
-
-
- while count <= 10 ;while 'count' is less than or equal to 10
- ...
- inc count ;increment count (count = count + 1)
- endwhile
-
- By using the debugger you'd see this on the bottom screen line before
- the WHILE command was executed, if 'count' had a value of 15:
-
- 5: WHILE 15 <= 10
-
- The debugger pauses prior to executing each line and shows you the
- script line number it's about to execute (5 in the example above)
- followed by a colon and the command. But instead of showing you the
- variable names it first REPLACES the variable names with the data that
- is stored in the variable. Your mistake would then be obvious (15
- isn't less than or equal to 10), and you could abort the script and
- modify it so that 'count' was properly initialized to whatever it
- should be initialized to before entering the loop:
-
- assign count 1 ;this was missing... now the loop works fine
- while count <= 10
- ...
- inc count ;increment count (count = count + 1)
- endwhile
-
- 3. Variable mix-ups. You think variable 'Y' is holding a certain value,
- but you're mistaken and actually variable 'X' has the value you
- wanted. Using the debugger, with the values of variables displayed on
- the status line, you'll be able to pick up the mistake.
-
- 4. Logic errors. You're comparing two values, and either get the
- arguments mixed up left to right, or use the wrong operator in between
- (less than instead of greater than, etc). If you're expecting an IF
- or WHILE comparison to be TRUE, and it turns out to be false and skips
- commands you didn't expect it to, then you'll know that the problem is
- in your IF or WHILE comparison and can take a closer look. Often you
- can only pick this up by executing the script line-by-line in debug
- mode and watching closely. With the script running at full tilt you
- might not even realize that the comparison had proven false, and that
- one or more script lines were skipped as a result.
-
- There are all sorts of tiny errors like this that can cause scripts (and
- computer programs in general) to malfunction. If you ever wondered where
- program bugs come from... and thought it was due to shabby work, now you
- know different. <grin> The types of errors that cause script or program
- bugs are often so subtle that the only way to find them is to execute the
- program one line at a time... and even then you'll often have to watch
- carefully.
-
- 7.2 Using the Debugger
-
- To activate the debugger while a script is EXECUTING simply press [Alt-Q]
- (the usual job/script 'Q'uit command), then select "Script DEBUG [Step-
- by-step]" or "Script DEBUG [Animate]" from the Alt-Q menu. To turn
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 76
-
-
-
- debugging off, press [Alt-Q] and select "Script DEBUG [OFF]".
-
- In 'step-by-step' mode, the debugger displays each script line as
- outlined above, then waits for you to press the [Space] bar, [Enter] key,
- or left mouse button before it executes the line. In 'animate' mode,
- each script line is displayed momentarily before it executes, running at
- about 2 lines per second (to quickly zero in on the general area of a
- problem, when you're not quite sure where to start looking).
-
- You can also turn step-by-step and animate mode on/off around lines of
- your script where you suspect a problem:
-
- DEBUG 1 ;turn step-by-step mode ON
- DEBUG 2 ;turn animate mode ON
- DEBUG 0 ;turn step-by-step or animate mode OFF
-
- This is how you'll normally turn debug mode on and off, by adding DEBUG
- commands to your script in and around lines where you suspect a problem.
- Pressing the [Alt-Q] key and selecting a debug mode manually might be
- difficult to time properly.
-
- When either debug mode is on, Icom will pause prior to executing each
- line and will show you the line it's about to execute (with all the
- relevant variables replaced to show the VALUE of the variable). To see
- the script line in its original format (with the variable names instead
- of the contents of the variables), press and hold the [Alt] key. When
- you release the [Alt] key the line will revert back to the original
- format, showing the value of the variables. This can be helpful for
- cases where you get two variables mixed up, and you intended to use X,
- but you used Y by accident. When you see the 'wrong' value displayed,
- hold down the [Alt] key to see the NAME of the variable you used. You
- might have used the wrong variable by mistake. The [Alt] key can also be
- useful for pausing animate mode temporarily. Animate mode pauses for as
- long as you hold the [Alt] key down (and you can also press [Alt-Q]
- before releasing [Alt] to switch from animate mode to step-by-step mode).
-
- If the line is longer than can be displayed on the screen, use the
- [Left], [Right] cursor arrow keys (or mouse left/right motion) to scroll
- the line left/right.
-
- If you find a bug and wish to abort the script, again it's done via the
- [Alt-Q] menu by selecting "Abort Script Only". To get a quick summary of
- all these keys, press the [F1] help key when in either debugging mode.
-
- NOTE 1: Script commands which permit OTHER commands to be executed if a
- certain condition is true (DIREXIST, EXIST, OFFLINE, ONLINE, etc) will
- show up on the debug display TWICE if the condition is true. For
- example, with an OFFLINE command you'd see something like this on the
- debug display first:
-
- 5: OFFLINE GOTO exit_script
-
- ...then, if the modem WAS offline (the condition was true), you'd see
- this on the debug display, before the specified command was executed:
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 77
-
-
-
- 5: GOTO exit_script
-
- The same line number is displayed since the second command is on the same
- line.
-
- NOTE 2: If a command takes a parameter that will be changed as soon as
- you press the [Space] bar ('ADD z y x' for example would assign y + x to
- z immediately), then the debugger doesn't bother showing you the contents
- of the variable, and simply shows you the variable name. It's more
- useful (and easier to follow) to be able to see which variable you're
- assigning to, rather than looking at something like this:
-
- 7: ADD 0 123 456 ;where 5 would be the CONTENTS of a variable
-
- (Where '0' just happened to be the contents of 'z' BEFORE the ADD command
- was executed.) In these cases, the debugger displays:
-
- 7: ADD myvariable 123 456
-
- This applies only to certain commands where it may prove confusing to
- display the contents of the variable rather than the variable name, as
- with ADD above, where you might get the impression that the ADD had
- already taken effect and the WRONG value had been stored (which would not
- be the case, since the command has not executed as yet). There are some
- cases, such as with ADDSLASH where a variable IS going to be changed, but
- the debugger does display the contents of the variable:
-
- 8: ADDSLASH "C:\SOMEDIR"
-
- is more useful than:
-
- 8: ADDSLASH mydirectory
-
- would be. If you want to check the contents of such variables AFTER the
- command executes, and you don't have any lines below that use the
- variable, use the DEBUG command as outlined below.
-
- 7.3 Checking the Contents of a Single Variable
-
- To have the debugger simply display the contents of a single variable to
- the screen and wait for you to press [Space] or [Enter], specify the
- variable name after the DEBUG command:
-
- variable myvariable ;define a variable called 'myvariable'
- ...
- GETS myvariable 10 ;get keyboard input to 'myvariable'
- DEBUG myvariable ;pause and display the contents of 'myvariable'
- ...
- capture "NEWCAP.CAP" ;open a new capture file
- DEBUG $CAP_FNAME ;display the full '$CAP_NAME' (drive/path, etc).
-
- The two DEBUG commands above would might display something like this:
-
- 10: DEBUG "User Input"
-
-
-
-
- Intellicomm v2.01 SCRTUTOR.DOC 78
-
-
-
- 20: DEBUG "C:\ICOM\CAP\NEWCAP.CAP"
-
- This allows you to see the contents of a variable without actually
- 'doing' anything. You don't have to be in DEBUG mode (i.e. by pressing
- [Alt-Q]) to use this command. You can place them anywhere in your
- script, wherever you suspect a problem, and Icom will switch to debug
- mode temporarily to display the contents of the specified variable.
-
- If you ARE in debug mode and a 'DEBUG variable' command is found, the
- command is simply displayed as any other command would be. If in animate
- mode, this use of DEBUG also causes the debugger to pause and wait for
- [Space] or [Enter] before continuing in animate mode.
-
- Again, press and hold the [Alt] key to see the original script line (the
- variable name instead of the contents of the variable). After you've
- checked the contents of the variable, press [Space] or [Enter] (or the
- left mouse button) to continue running the script at full speed (or to
- continue in Animate mode if you were in Animate mode previously), or
- again use the [Alt-Q] menu to either abort the script, or go into step-
- by-step or animate mode, etc.
-
- 7.4 Debug Hotkeys
-
- When debug mode is active, most of the Icom hotkeys are disabled. You
- cannot, for example, press [Alt-M] to switch to the Main Menu. You can,
- however, use [Alt-A] to enter the editor, [Alt-J] to 'Jump' to a DOS
- shell, [Alt-N] (user-defined Hotkey 1), [Alt-O] (user-defined hotkey 2),
- and [Alt-V] to run your external archiver. When you finish with the
- called task, you'll be returned to the debug display exactly as it was
- before you pressed the hotkey.
-
- IMPORTANT: If you use [Alt-A] to run the editor and change the script
- Icom is running, the changes will not take effect until you abort and re-
- start the script. Icom loads scripts into memory, and changing the
- script file (on-disk) in the editor doesn't affect the script in memory
- that Icom is running.
-